commit 69f117bf78291ed6d96593cb1cebefb8fbb6bfb2 Author: Evgeniy Kozhuhovskiy Date: Thu Dec 30 16:00:36 2004 +0000 Initial revision diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..bcb4f0b --- /dev/null +++ b/CHANGES @@ -0,0 +1,60 @@ +* New: now "bforce" can start outgoing sessions simply on stdin/stdout. + (command line option "-o") +* New: file boxes support. New config keywords "filebox" and + "filebox_directory" +* Bugfix: now "bforce" will remove .bsy locks immediately after + disconnection +* New: implemented CRAM-MD5 authentication in the BinkP protocol +* New: new command line option "-c" in the "bfstat" utility +* New: BinkP seems to be working fine now +* Bugfix: some file names could be spoiled on the Hydra protocol while + receiving (it is a bug with receiving files with the name "d" instead + of the real one) +* New: implementation of the YooHoo handshake protocol +* New: now will create .csy locks while dialing and convert it to + the .bsy only at handshake +* Bugfix: now daemon will not call to the nodes marked as Hold/Down + in a nodelist +* New: added sessions history loging. New config keyword "sessions_history" + For the history file format look sources. +* Bugfix: Hydra didn't send "short" file name, as a result some mailers + with strict checks could not receive files with long names :)) +* New: removed check for "short" file name length in the Hydra + +0.22 (31-07-2000) + +* Bugfix: at incoming sessions used speed limit for outgoing sessions +* Bugfix: RH1 mode didn't work correctly +* Bugfix: outgoing BinkP password protected sessions allways fail + with invalid password error +* Bugfix: files from the AmigaDos Outbound send in incorrect order +* New: passwords are case insensitive now (again) +* New: improved EMSI handshake, now it should work better with systems + using Cisco or something like that with login prompt +* New: added writing of the remote intro to log (like *ico). To control + this feature added new option "[No]Intro" +* New: protocol selection options now works at incoming sessions too +* New: added support for modem chat commands, e.g "ATz| ATm0|", mailer + will wait for modem response ("OK" or "ERROR") after sending each + substring and only then send the next one +* Bugfix: file masks checker didn't work correctly than '!' (not) + prefix was used. Now "DelayFiles", "SkipFiles" should work normaly +* New: Added new expression elements: Exist , Mailer , Port +* New: Added autoconfiguration of UUCP lock files directory +* Bugfix: daemon could call even to "-Unpublished-" phone if it was + specified in override. +* Bugfix: could not parse received EMSI data packet if character ']' was + escaped as '\5d' by remote mailer (e.g. DVMMail do such escaping) +* New: added support for Tx/Rx windows and ASC/UUE packets in the Hydra +* Bugfix: files skipped by remote mailer was not really skipped :) +* New: extended algorithm of renaming received file if file with such name + allready exist in the inbound directory: + - For netmail packets and '.tic' files: generate new random name + - For arcmail packets: rotate extension characters, as most other mailers do + - For file requests: allways overwrite existing file + - For all other files: add numeric extension as in previous versions +* New: added ability to recode file names and intro text to another charset + then sending/receiving. Recode tables are compartible with HPT. New + config keywords: "Recode_file_in", "Recode_file_out", "Recode_intro_in" + diff --git a/CHANGES.kst b/CHANGES.kst new file mode 100644 index 0000000..e8fbb66 --- /dev/null +++ b/CHANGES.kst @@ -0,0 +1,67 @@ +0.22.7.kst1 +=========== + + * Attempt to fix warnings, when compiling with -Wall. + + make update -- install only binaries. + * Better EMSI handling, when calling to cisco. + + Correct ZMH support in daemon. + * Some fixes in contributed perl scripts. + +0.22.7.kst2 +=========== + + + Added option --with-uucp-lockdir=... to configure. + * Using strncpy(3) instead of strcpy(3) if possible. + + Added patches by Maxi Rovnich @ 2:5030/872: + + Support for maximum 'no dialtone' count. + + Support for download resyncing, while checking for free space. + + Ignore all files, but *.pnt, *.req, *.?lo and *.?ut in BSO. + +0.22.7.kst3 +=========== + + * Compilation failed with --disable-hangup-watch-cd. Fixed. + + Ability to write daemon pid in file. + * -f option had reverse meaning. Thanks to Eugene Korovin @ 2:5080/196.72 + + -q option terminates daemon process (only if pidfile is used). + +0.22.7.kst4 +=========== + + * Hydra was broken in kst2. Fixed. + + Bidirectional session drops only if rxcps and txcps are less than + mincps at the same time. + +0.22.7.kst5 +=========== + + + port tcpip patch by Serge N. Pokhodyaev @ 2:5020/1838 + * lock fix, when outbound on not lockable filesystem. + Patch by Andrew Dolgov @ 2:5030/394.41 + +0.22.7.kst6 +=========== + + * traffic wasn't shown if no files in boxes. + Patch by Alexander Shiyan @ 2:5030/39.2 + * bfstat now correctly shows age of files. + Patch by Alexander Shiyan @ 2:5030/39.2 + * logging 'undefined cmd' fixed. + Thanks to Pavel I.Osipov @ 2:5020/770.50 + +0.22.8.kst7 +=========== + + Some changes taken from 0.22.8 by Alexander Belkin: + * some bugfixes + + new environment variable $RC (session return code) + + sending of EMSI_ACK every time after recving of EMSI_DAT + + support for nodelist IBN flag + +0.22.8.kst8 +=========== + + * fixed bug with flags CM in override + * fixed bug with sending HUP to daemon + diff --git a/CHANGES.ugenk b/CHANGES.ugenk new file mode 100644 index 0000000..de34c42 --- /dev/null +++ b/CHANGES.ugenk @@ -0,0 +1,26 @@ +0.22.8.ugenk1 +============= + + initial release, based on bforce 0.22.8.kst8 + * fixed problem with worktime detecting + + makefiles fixed (removed make update, now make install installs config files with extension .sample) + + added --with-user and --with-group options to ``configure'' script. + + installation directories by default are compliance with default fidogate installation + +0.22.8.ugenk2 +============= + * pathes by Andrey Slusar @ 2:467/126 + (total 12: patch-bforce.c, patch-bfstat.c, patch-daemon.c, patch-expression.y, + patch-nlookup.c, patch-prot_binkp.c, patch-prot_emsi.c, patch-prot_yoohoo.c, patch-prot_zmrecv.c, + patch-prot_zmsend.c, patch-sess_call.c, patch-sess_stat.c) + + added syslog support (see SYSLOG) + + fixed nlookup (broken in ugenk1) + + spec file now goes with bforce + +0.22.8.ugenk3 +============= + + fixed working with syslog (not tested yet, any volonteers?) + * some bugfixes + +0.22.8.ugenk4 +============= + + fixed problems with license (thnx to Jonathan Gonzales V. from gnu.org) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + , 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/INSTALL b/INSTALL new file mode 100644 index 0000000..0901042 --- /dev/null +++ b/INSTALL @@ -0,0 +1,175 @@ +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. Type `make install' to install the programs and any data files and + documentation. + + 4. 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'. + +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/INSTALL.ru b/INSTALL.ru new file mode 100644 index 0000000..47bc79d --- /dev/null +++ b/INSTALL.ru @@ -0,0 +1,131 @@ +В этом файле описывается процесс установки и настройки +фидонет-совместимого мейлера bforce 0.22.8.ugenk1. + +В данном документе приняты следующие обозначения: + + - путь, куда вы распаковали тарболл с исходными + текстами bforce 0.22.8.ugenk1 (далее bforce) +Тарболл - файл с расширением tar.gz, или tar.bz2 + + +Требования к системе +==================== + +Для компиляции bforce вам потребуется компилятор (для +gnu/bsd-систем gcc), так же GNU make (make для линукс, +gmake для bsd). + +Обратитесь к документации по вашей системе того, что бы +узнать как установить вышеперечисленное программное обеспечение. + + +Процесс компиляции +================== + +Распакуйте тарболл следующими командами: + +gzip -d bforce-0.22.8.ugenk1.tar.gz +или +bzip2 -d bforce-0.22.8.ugenk1.tar.bz2 + +tar -xvf bforce-0.22.8.ugenk1.tar + +Перейдите в директорию bforce-0.22.8.ugenk1/source: +cd /bforce-0.22.8.ugenk1/source + +Для создания Makefile, который наиболее подходит к вашей +системе, наберите: + +./configure --help + +и внимательно прочитайте предлагаемую справку. +Если вам не понятна предлагаемая справка, то просто запустите: + +./configure + +При необходимости исправьте Makefile для ваших нужд. +Запустите команду make (для bsd - gmake): + +make + +В случае ошибок при выполнении команды make пишите bugreport на +e.kozhuhovskiy@gmail.com + +Возможно, прийдется пересоздать configure с помощью autoconf + +Поздравляем, компиляция завершилась успешно. +Для установки bforce наберите: + +make install + +Для bsd: + +gmake install + + +Настройка +========= + +Для нормальной работы вам нужно отредактировать конфигурационные файлы +bforce. По умолчанию они находятся в /usr/local/fido/etc и называются +bforce.conf - основной конфигурационный файл bforce +bforce.passwd - файл определения паролей на сессии +bforce.subst - файл переопределения данных из nodelist +freq.dirs - файл задания списка директорий для freq-запросов +freq.aliases - файл задания magic freqests + +Так же вам необходимо подправить файл outman. По умолчанию он лежит в +/usr/local/fido/bin. outman - это скрипт, вызываемый вами для создания +прозвонок, файловых запросов и файл-аттачей на узлы ftn. + + +Использование +============= + +bforce - основной файл bforce, служит для запуска +демона, исходящих звонков и запуска из-под mgetty\portslave для приема +входящих звонков. +Попробуйте bforce --help + + +bfindex - служит для обновления индексных файлов (перекомпиляции) +нодлистов. Испрользование: bfindex + +bfstat - служит для показа почтовой очереди. Использование: bfstat + +nlookup - служит для поиска информации в нодлисте. Использование: +nlookup + +outman - см. "Настройка". Попробуйте outman --help + + +Дополнительные утилиты +====================== + +Дополнительные утилиты для bforce находятся в /contrib: +bflan - bforce log analyzer +callout.sh - скрипт для отзвонки на аплинков +outman - скрипт outman +timesync.tcl - скрипт для синхорнизации времени +init.d/bforce - init-скрипт для RedHat +init.d/bforce.debian - init-скрипт для non-RedHat +bfha - bforce history analyzer (bfha) +bfha/README - bfha README +bfha/bfha.pl - собственно, bfha +u-srif - продвинутый freq-процессор +u-srif/u-srif-index.py \ с поддержой отчетов, +u-srif/u-srif-lookup.py \ ограничений, +u-srif/u-srif.py \ индексации файловой базы, +u-srif/conf \ что значительно ускоряет +u-srif/conf/report.footer \ работу. +u-srif/conf/report.header \ Написан на python. +u-srif/conf/u-srif.aliases \ -------------------- +u-srif/conf/u-srif.conf \ ------------------- +u-srif/conf/u-srif.dirs \ ------------------ +u-srif/lib / ------------------ +u-srif/lib/uconfig.py / ------------------- +u-srif/lib/udbase.py / -------------------- +u-srif/lib/ufido.py / --------------------- +u-srif/lib/unodestat.py / ---------------------- +u-srif/lib/utmpl.py / ----------------------- +u-srif/lib/uutil.py / ------------------------ diff --git a/README b/README new file mode 100644 index 0000000..b0916d9 --- /dev/null +++ b/README @@ -0,0 +1,32 @@ +$Id$: + +BinkleyForce FTN mailer +----------------------- + +BinkleyForce is a simple ifcico like FTN mailer. It can works via +TCP/IP as well as on modem links. Look sample configs for more +information. + +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. See the COPYING file for further information. + +Known Bugs +---------- + - BinkD use and expect local file time at BinkP sessions, but + BinkleyForce allways use UTC time (?) + +Bug Reports +----------- + + E-Mail : adb@newmail.ru + FidoNet : Alexander Belkin, 2:5020/1398.11 + +New Versions +------------ + + http://adb.newmail.ru + + +Copyright (c) 1998-2000 Alexander Belkin, Moscow, Russia. diff --git a/README.kst b/README.kst new file mode 100644 index 0000000..0e732d1 --- /dev/null +++ b/README.kst @@ -0,0 +1,14 @@ +BinkleyForce FTN mailer (Branch KST) +------------------------------------ + +Bug Reports +----------- + + E-Mail : kst@moecho.org + FidoNet : Konstantin Stepanenkov, 2:5030/1251 + +New Versions +------------ + + http://kst.spb.ru/bforce/ + diff --git a/README.ugenk b/README.ugenk new file mode 100644 index 0000000..b6fbfbe --- /dev/null +++ b/README.ugenk @@ -0,0 +1,14 @@ +BinkleyForce FTN mailer (Branch ugenk) +------------------------------------ + +Bug Reports +----------- + + E-Mail : e.kozhuhovskiy@gmail.com + FidoNet : Evgeniy Kozhuhovskiy, 2:450/256, 2:450/267 + +New Versions +------------ + + http://ugenk.bas-net.by/ + diff --git a/SYSLOG b/SYSLOG new file mode 100644 index 0000000..1c021e9 --- /dev/null +++ b/SYSLOG @@ -0,0 +1,10 @@ +Now binkleyforce supports logging to syslog (see syslogd(8) for +details) + +It uses LOG_UUCP facility, LOG_PID option. LOG_ERR and LOG_NOTICE +levels are used. + +To enable it, uncomment line 19 in source/include/logger.h +( /* #define USE_SYSLOG */ ) + +TODO: add option to ``configure'' script \ No newline at end of file diff --git a/TODO b/TODO new file mode 100644 index 0000000..b76ed36 --- /dev/null +++ b/TODO @@ -0,0 +1,11 @@ +"-" - bugfix +"+" - feature + + + - sed detection in makefile + + [io_modem.c] add random and smart algorythms selecting of tty. + smart means (1) write time stat for every line and (2) evenly + select a line to make a call + + HOLDALL emsi option, if specified flag exists + + add bind_ip option + - fix Exec feature \ No newline at end of file diff --git a/build-stamp b/build-stamp new file mode 100644 index 0000000..e69de29 diff --git a/configure-stamp b/configure-stamp new file mode 100644 index 0000000..e69de29 diff --git a/contrib/bfha/README b/contrib/bfha/README new file mode 100644 index 0000000..0352a06 --- /dev/null +++ b/contrib/bfha/README @@ -0,0 +1,19 @@ +Данный скрипт предназначен для генерации статистики о работе мейлера +binkleyforce путём анализа создаваемого им файла истории сессий (параметр +`history_file' в bforce.conf). Статистика генерится за предыдущие сутки от +момента запуска скрипта и постится в заданную ньюсгруппу. Доступны два типа +статистики. + +Перед первым запуском рекомендуется изменить значение конфигурационных +переменных -- они находятся в начале скрипта. + +Известные баги: + + 1. Hе учитывается случай, когда файл истории сессий повёрнут + logrotate'ом (может потеряться часть статистики) + 2. Hеправильно считает cps (завышает), если трафик в обе стороны + +Автор скрипта: Serge N. Pokhodyaev, 2:5020/1838, + +Распространяется под GNU GPL. + diff --git a/contrib/bfha/bfha.pl b/contrib/bfha/bfha.pl new file mode 100644 index 0000000..3b24768 --- /dev/null +++ b/contrib/bfha/bfha.pl @@ -0,0 +1,575 @@ +#!/usr/bin/perl + +# +# bfha -- binkleyforce history analyzer +# +# Copyright (C) 2000 Serge N. Pokhodyaev +# +# E-mail: snp@ru.ru +# Fido: 2:5020/1838 +# +# +# 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. +# +# +# $Id$ +# + +# +# Генерит статистику за предыдущий день +# + +# +# TODO: +# +# 1. Учесть случай, когда лог повёрнут logrotate'ом +# +# Known bugs: +# +# 1. Hеправильно считает cps (завышает) если трафик в обе стороны +# + +use strict; +use Time::Local; +use POSIX qw(strftime); + +my $PROGNAME = 'bfha'; +my $VERSION = '$Revision$ '; + +######## Configurable part ################################################### + +my $inews = "/usr/bin/inews -h -O -S"; + +my $log = "/var/spool/fido/history"; + +my $rep_newsgroups = "ftn.1838.stat"; +my $rep_from = "\"Statistics generator\" "; +my $rep1_subj = "Sessions history"; +my $rep2_subj = "Sessions history"; +my $rep3_subj = "Links statistics"; + +my $count_failed = 1; + +#my %line_names = ( +# "ttyS1" => "Modem", +# "tcpip" => "IP" +#); + +############################################################################## + +my $devel = 0; + +my (%st, %lines, %nodes, @nodes_sorted); +my @tm; +my $time; + +die "Usage: $PROGNAME [-d]\n" if (!((0 == $#ARGV) && ($ARGV[0] eq '-d')) && !(-1 == $#ARGV)); +$devel = 1 if ((0 == $#ARGV) && ($ARGV[0] eq '-d')); + +$log = "./history" if ($devel); + +# Make version string +# +$VERSION =~ s/(\$Rev)ision:\s([\d.]+).*/$PROGNAME\/$2/; + +# Get time of 0:00:00 of yesterday +# +@tm = localtime(time - 86400); +$tm[0] = 0; # sec +$tm[1] = 0; # min +$tm[2] = 0; # hours +$time = timelocal(@tm); + +# At first read logs +# +undef %st; +undef %lines; +undef %nodes; +die "Log reading error\n" if (0 != log_read($time)); + +@nodes_sorted = sort(node_cmp keys(%nodes)); + +# Now generate statistics +# +out_close(); +#rep1(); +rep2(); +rep3(); + + +sub log_read + { + my $i; + my $t; + my @l; + + die if (0 != $#_); + + $t = $_[0]; + + open(LOG, "< $log") || die("Can't open $log: $!\n"); + while () + { + chomp; + @l = split(/,/); + return 1 if ($#l != 11); + return 1 if (! ($l[4] =~ /[IO]/)); + + # Check date + # + next if ($l[2] < $t); + last if ($l[2] >= ($t + 86400)); + + # Entries without address + # + if ($l[1] eq '') + { + next if (0 == $count_failed); + $l[1] = 'failed' if (0 != $count_failed); + } + + # Remove domain + # + $l[1] =~ s/@.*$//; + + # Add statistics + # + $i = $#{$st{beg}} + 1; + + $lines{$l[0]}[$#{$lines{$l[0]}} + 1] = $i; + $nodes{$l[1]}[$#{$nodes{$l[1]}} + 1] = $i; + + $st{beg}[$i] = $l[2]; + $st{len}[$i] = $l[3]; + $st{addr}[$i] = $l[1]; + $st{line}[$i] = $l[0]; + $st{rc}[$i] = $l[5]; + $st{snt_nm}[$i] = $l[6]; + $st{snt_am}[$i] = $l[7]; + $st{snt_f}[$i] = $l[8]; + $st{rcv_nm}[$i] = $l[9]; + $st{rcv_am}[$i] = $l[10]; + $st{rcv_f}[$i] = $l[11]; + $st{islst}[$i] = 0; + $st{islst}[$i] = 1 if ($l[4] =~ /L/); + $st{isprot}[$i] = 0; + $st{isprot}[$i] = 1 if ($l[4] =~ /P/); + $st{type}[$i] = 'I' if ($l[4] =~ /I/); + $st{type}[$i] = 'O' if ($l[4] =~ /O/); + } + } + +######## rep1 ################################################################ + +sub rep1 + { + my ($i, $j); + my (%se, %se_t); + my $node; + + out_open($rep1_subj); + printf "Date: %s\n\n", strftime("%a, %e %b %Y", localtime($time)); + + $~ = "rep1_header"; + write; + + $~ = "rep1_body"; + $se_t{num_in} = 0; + $se_t{num_out} = 0; + $se_t{snt} = 0; + $se_t{rcv} = 0; + $se_t{len} = 0; + foreach $node (@nodes_sorted) + { + $se{num_in} = 0; + $se{num_out} = 0; + $se{snt} = 0; + $se{rcv} = 0; + $se{len} = 0; + for ($i = 0; $i <= $#{$nodes{$node}}; ++$i) + { + $j = $nodes{$node}[$i]; + ++$se{num_in} if ($st{type}[$j] eq 'I'); + ++$se{num_out} if ($st{type}[$j] eq 'O'); + $se{snt} += $st{snt_am}[$j] + $st{snt_nm}[$j] + $st{snt_f}[$j]; + $se{rcv} += $st{rcv_am}[$j] + $st{rcv_nm}[$j] + $st{rcv_f}[$j]; + $se{len} += $st{len}[$j]; + } + $se{time} = time_int2str($se{len}); + # FIXME (cps) + $se{cps} = div_int(($se{snt} + $se{rcv}), $se{len}); + write; + + $se_t{num_in} += $se{num_in}; + $se_t{num_out} += $se{num_out}; + $se_t{snt} += $se{snt}; + $se_t{rcv} += $se{rcv}; + $se_t{len} += $se{len}; + } + + $~ = "rep1_footer"; + $se_t{time} = time_int2str($se_t{len}); + # FIXME (cps) + $se_t{cps} = div_int(($se_t{snt} + $se_t{rcv}), $se_t{len}); + write; + + print "\n"; + out_close(); + + +format rep1_header = +╔═════════════════╤══════════╤═══════════╤════════════╤═══════════╤═══════╗ +║ System │ Sessions │ Sent │ Received │ Time │ CPS ║ +║ address │ in out │ bytes │ bytes │ online │ ║ +╠═════════════════╪══════════╪═══════════╪════════════╪═══════════╪═══════╣ +. + +format rep1_body = +║ @<<<<<<<<<<<<<< │ @>> @>> │ @>>>>>>>> │ @>>>>>>>>> │ @>>>>>>>> │ @>>>> ║ +$node, $se{num_in}, $se{num_out}, $se{snt}, $se{rcv}, $se{time}, $se{cps} +. + +format rep1_footer = +╟─────────────────┼──────────┼───────────┼────────────┼───────────┼───────╢ +║ TOTAL │ @>> @>> │ @>>>>>>>> │ @>>>>>>>>> │ @>>>>>>>> │ @>>>> ║ +$se_t{num_in}, $se_t{num_out}, $se_t{snt}, $se_t{rcv}, $se_t{time}, $se_t{cps} +╚═════════════════╧══════════╧═══════════╧════════════╧═══════════╧═══════╝ +. + } + +######## rep2 ################################################################ + +sub rep2 + { + my ($i, $j); + my @t; + my ($t1, $t2, $str, $lv); + my $node; + my %se; + + out_open($rep2_subj); + printf "Date: %s\n\n", strftime("%a, %e %b %Y", localtime($time)); + + $~ = "rep2_header"; + write; + + $~ = "rep2_body"; + foreach $node (@nodes_sorted) + { + $se{snt} = 0; + $se{rcv} = 0; + $se{len} = 0; + for ($i = 0; $i <= 95; ++$i) + { + $t[$i] = 0; + } + for ($i = 0; $i <= $#{$nodes{$node}}; ++$i) + { + $j = $nodes{$node}[$i]; + + # Fill array + # + $t1 = $st{beg}[$j] - $time; + $t2 = $t1 + $st{len}[$j]; + $t2 = 86399 if ($t2 > 86399); + $t1 = div_int($t1, 900); + $t2 = div_int($t2, 900); + while ($t1 <= $t2) + { + $t[$t1++] = 1; + } + + $se{snt} += $st{snt_am}[$j] + $st{snt_nm}[$j] + $st{snt_f}[$j]; + $se{rcv} += $st{rcv_am}[$j] + $st{rcv_nm}[$j] + $st{rcv_f}[$j]; + $se{len} += $st{len}[$j]; + } + $se{time} = time_int2str($se{len}); + # FIXME (cps) + $se{cps} = div_int(($se{snt} + $se{rcv}), $se{len}); + + # Visualize + # + $i = 0; + $str = ""; + if ($t[$i++]) + { + $str = $str . "▐"; + } + else + { + $str = $str . "│"; + } + while ($i < $#t) + { + $lv = 0; + $lv += 1 if ($t[$i++]); + $lv += 2 if ($t[$i++]); + + if (0 == $lv) + { + if (div_rest(($i - 1), 8) == 0) + { + $str = $str . "│"; + } + else + { + $str = $str . " "; + } + } + elsif (1 == $lv) + { + $str = $str . "▌"; + } + elsif (2 == $lv) + { + $str = $str . "▐"; + } + elsif (3 == $lv) + { + $str = $str . "█"; + } + } + if ($t[$i]) + { + $str = $str . "▌"; + } + else + { + $str = $str . "│"; + } + + write; + } + + $~ = "rep2_footer"; + write; + + out_close(); + + +format rep2_header = + 0 2 4 6 8 10 12 14 16 18 20 22 24 + ├─┴─┼─┴─┼─┴─┼─┴─┼─┴─┼─┴─┼─┴─┼─┴─┼─┴─┼─┴─┼─┴─┼─┴─┤ +. + +format rep2_body = +@<<<<<<<<<<<<<<@|||||||||||||||||||||||||||||||||||||||||||||||| +$node, $str +. + +format rep2_footer = + ├─┬─┼─┬─┼─┬─┼─┬─┼─┬─┼─┬─┼─┬─┼─┬─┼─┬─┼─┬─┼─┬─┼─┬─┤ + 0 2 4 6 8 10 12 14 16 18 20 22 24 +. + } + +######## rep3 ################################################################ + +sub rep3 + { + my $node; + my (%se, %se_t); + my ($i, $j); + + out_open($rep3_subj); + printf "Date: %s\n\n", strftime("%a, %e %b %Y", localtime($time)); + + $~ = "rep3_header"; + write; + + $~ = "rep3_body"; + $se_t{num_in} = 0; + $se_t{num_out} = 0; + $se_t{time_in} = 0; + $se_t{time_out} = 0; + $se_t{snt} = 0; + $se_t{rcv} = 0; + $se_t{time} = 0; + foreach $node (@nodes_sorted) + { + $se{num_in} = 0; + $se{num_out} = 0; + $se{time_in} = 0; + $se{time_out} = 0; + $se{snt} = 0; + $se{rcv} = 0; + $se{time} = 0; + for ($i = 0; $i <= $#{$nodes{$node}}; ++$i) + { + $j = $nodes{$node}[$i]; + ++$se{num_in} if ($st{type}[$j] eq 'I'); + ++$se{num_out} if ($st{type}[$j] eq 'O'); + $se{time_in} += $st{len}[$j] if ($st{type}[$j] eq 'I'); + $se{time_out} += $st{len}[$j] if ($st{type}[$j] eq 'O'); + $se{snt} += $st{snt_am}[$j] + $st{snt_nm}[$j] + $st{snt_f}[$j]; + $se{rcv} += $st{rcv_am}[$j] + $st{rcv_nm}[$j] + $st{rcv_f}[$j]; + $se{time} += $st{len}[$j]; + } + + # Total counters + # + $se_t{num_in} += $se{num_in}; + $se_t{num_out} += $se{num_out}; + $se_t{snt} += $se{snt}; + $se_t{rcv} += $se{rcv}; + $se_t{time} += $se{time}; + $se_t{time_out} += $se{time_out}; + $se_t{time_in} += $se{time_in}; + + # Output string + # + # FIXME (cps) + $se{cps} = dash_if_zero(div_int(($se{snt} + $se{rcv}), $se{time})); + $se{time} = time_int2str($se{time}); + $se{time_in} = time_int2str($se{time_in}); + $se{time_out} = time_int2str($se{time_out}); + $se{num_in} = dash_if_zero($se{num_in}); + $se{num_out} = dash_if_zero($se{num_out}); + $se{rcv} = shrink_size(dash_if_zero($se{rcv})); + $se{snt} = shrink_size(dash_if_zero($se{snt})); + write; + } + + $~ = "rep3_footer"; + # FIXME (cps) + $se_t{cps} = dash_if_zero(div_int(($se_t{snt} + $se_t{rcv}), $se_t{time})); + $se_t{time} = time_int2str($se_t{time}); + $se_t{time_in} = time_int2str($se_t{time_in}); + $se_t{time_out} = time_int2str($se_t{time_out}); + $se_t{num_in} = dash_if_zero($se_t{num_in}); + $se_t{num_out} = dash_if_zero($se_t{num_out}); + $se_t{rcv} = shrink_size(dash_if_zero($se_t{rcv})); + $se_t{snt} = shrink_size(dash_if_zero($se_t{snt})); + $~ = "rep3_footer"; + write; + + print "\n"; + out_close(); + + +format rep3_header = +╔════════════════╦═══════════════════════════╦══════════╦═════════════╦═══════╗ +║ ║ Sessions/Online ║ Time ║ Traffic ║ ║ +║ Address ╠═════════════╦═════════════╣ online ╠══════╦══════╣ CPS ║ +║ ║ Incoming ║ Outgoing ║ ║ Rcvd ║ Sent ║ ║ +╠════════════════╬═══╤═════════╬═══╤═════════╬══════════╬══════╬══════╬═══════╣ +. + +format rep3_body = +║ @<<<<<<<<<<<<<<║@>>│@>>>>>>> ║@>>│@>>>>>>> ║@>>>>>>>> ║@>>>>>║@>>>>>║@>>>>> ║ +$node, $se{num_in}, $se{time_in}, $se{num_out}, $se{time_out}, $se{time}, $se{rcv}, $se{snt}, $se{cps} +. + +format rep3_footer = +╟────────────────╫───┼─────────╫───┼─────────╫──────────╫──────╫──────╫───────╢ +║ TOTAL ║@>>│@>>>>>>> ║@>>│@>>>>>>> ║@>>>>>>>> ║@>>>>>║@>>>>>║@>>>>> ║ +$se_t{num_in}, $se_t{time_in}, $se_t{num_out}, $se_t{time_out}, $se_t{time}, $se_t{rcv}, $se_t{snt}, $se_t{cps} +╚════════════════╩═══╧═════════╩═══╧═════════╩══════════╩══════╩══════╩═══════╝ +. + } + +############################################################################## + +sub shrink_size + { + die if (0 != $#_); + + return $_[0] if ($_[0] < 1024); + return sprintf("%.1fk", $_[0] / 1024) if ($_[0] < 1048576); + return sprintf("%.1fM", $_[0] / 1048576); + } + +sub dash_if_zero + { + die if (0 != $#_); + + return "-" if (0 == $_[0]); + return $_[0]; + } + +sub time_int2str + { + my $time; + my $h; + my $m; + my $s; + + die if (0 != $#_); + die if (86399 < $time); + + return "-:--:--" if (0 == $_[0]); + + $time = $_[0]; + $h = div_int($time, 3600); + $time = div_rest($time, 3600); + $m = div_int($time, 60); + $s = div_rest($time, 60); + + return sprintf("%d:%2.2d:%2.2d", $h, $m, $s); + } + +# Целочисленное деление +sub div_int + { + use integer; + + die if (1 != $#_); + + return 0 if ($_[1] == 0); + return $_[0] / $_[1]; + } + + +# Остаток от целочисленного деления +sub div_rest + { + die if (1 != $#_); + + return 0 if ($_[1] == 0); + return $_[0] - (div_int($_[0], $_[1]) * $_[1]); + } + +sub out_open + { + die if (0 != $#_); + + open(STDOUT, "| $inews") || die("Can't pipe to inews: $!\n") if (! $devel); + printf "Newsgroups: %s\n", $rep_newsgroups; + printf "From: %s\n", $rep_from; + printf "Subject: %s\n", $_[0]; + printf "X-FTN-Tearline: %s\n\n", $VERSION; + } + +sub out_close + { + close(STDOUT) if (! $devel); + } + +sub node_cmp + { + my (@na, @nb); + + @na = split('[:/.]', $::a); + @nb = split('[:/.]', $::b); + + # zone + return -1 if ($na[0] < $nb[0]); + return 1 if ($na[0] > $nb[0]); + + # net + return -1 if ($na[1] < $nb[1]); + return 1 if ($na[1] > $nb[1]); + + # node + return -1 if ($na[2] < $nb[2]); + return 1 if ($na[2] > $nb[2]); + + #point + return -1 if ($na[3] < $nb[3]); + return 1 if ($na[3] > $nb[3]); + + return 0; + } diff --git a/contrib/bflan b/contrib/bflan new file mode 100644 index 0000000..72c5576 --- /dev/null +++ b/contrib/bflan @@ -0,0 +1,384 @@ +#!/usr/bin/perl +# +# It is a log file analyser for 'binkleyforce' mailer. +# +# Copyright (c) 1998-99 by Alexander Belkin +# +# $Id$: +# +# If you have any questions, suggestions or wishes, feel free to contact +# with me. My address: 2:5020/1398.11@fidonet +# +# To post into news, use bflan |inews -h -O -S +$program_name = "bforce-lan v1.0/Perl/Linux"; +$station_name = "My Station"; +$log_file = "/var/log/bforce/bf-log.ttyS0"; +$news_header = "From: Statistic Robot \n". + "Newsgroups: junk\n". + "Subject: Sessions statistic.\n"; + +#main +#{ + if( &ReadLog($log_file) == 0 ) + { + print $news_header; + print "\n"; + print "\"$system_name\" statistic from <$TimeFirst> to <$TimeLast>\n"; + print "\n"; + &TotalStatistic(); + print "\n"; + &SessionsStatistic(); + } + exit(0); +#} + +sub ReadLog +{ + my($start); + + if( open( FLOG, $_[0] ) == 0 ) + { + print "Can't open log \"$_[0]\": $!\n"; + return 1; + } + $start = 0; + $cnt = 0; + $TimeFirst = ""; + $TimeLast = ""; + + # Read in information from logfile + + while( ) + { + chomp; + + ( $Mon, $Day, $Time, $Pid, $Text ) = split( /[ \t]+/, $_, 5 ); + + if( $TimeFirst eq "" ) + { + $TimeFirst = "$Mon $Day $Time"; + } + + if( $start == 0 ) + { + if( !defined($Connect[$cnt]) ) + { + $Address[$cnt] = ""; + $Connect[$cnt] = "?????"; + $InFiles[$cnt] = 0; + $OutFiles[$cnt] = 0; + $InBytes[$cnt] = 0; + $OutBytes[$cnt] = 0; + $Status[$cnt] = "U"; + $Success[$cnt] = " "; + } + if( $Text =~ /^calling/ ) + { + $Text =~ /^calling ([\d:\/.]+)/; + $PidsCall{$Pid} = $1; + $Calls{$1} = 0 if (!defined( $Calls{$1} )); + $Calls{$1}++; + } + elsif( $Text =~ /^connect/ ) + { + $Text =~ /^connect "\D*(\d+).*$/; + $Connect[$cnt] = $1; + } + elsif( $Text =~ /^TCP\/IP connect/ ) + { + $Connect[$cnt] = "TCPIP"; + } + elsif( $Text =~ /^outbound (\S+) session/ ) + { + $start = 1; + $Time =~ /^(..):(..):(..)$/; + $Start[$cnt] = ( $1 * 60 + $2 ) * 60 + $3; + $Direction[$cnt] = "O"; + $Address[$cnt] = $PidsCall{$Pid}; + $MySexyPid = $Pid; + next; + } + elsif( $Text =~ /^inbound (\S+) session/ ) + { + $start = 1; + $Time =~ /^(..):(..):(..)$/; + $Start[$cnt] = ( $1 * 60 + $2 ) * 60 + $3; + $Direction[$cnt] = "I"; +# $kAddress[$cnt] = $PidsCall{$Pid} if( defined($PidsCall{$Pid}) ); + $MySexyPid = $Pid; + next; + } + next; + } + + if( ($start == 1) && ($Pid eq $MySexyPid) ) + { + if( $Text =~ /^remote is password protected system/ ) + { + $Status[$cnt] = "P"; + } + elsif( $Text =~ /^remote is listed system/ ) + { + $Status[$cnt] = "L"; + } + elsif( $Text =~ /^remote is unlisted system/ ) + { + $Status[$cnt] = "U"; + } + elsif( $Text =~ /^[ \t]*Address :/ ) + { + next if( $Address[$cnt] ne "" ); + $Text =~ /^.+:[ \t]+([\d:.\/]+).*$/; + $Address[$cnt] = $1; + } + elsif( $Text =~ /^rcvd: \".+\" \d+/ ) + { + $Text =~ /^rcvd: \".+\" (\d+)/; + $InBytes[$cnt] += $1; + $InFiles[$cnt] ++; + } + elsif( $Text =~ /^sent: \".+\" \d+/ ) + { + $Text =~ /^sent: \".+\" (\d+)/; + $OutBytes[$cnt] += $1; + $OutFiles[$cnt] ++; + } + elsif( $Text =~ /^session rc = \d+/ ) + { + $Text =~ /^session rc = (\d+)/; + if( $1 != 0 ) + { + $Success[$cnt] = "A"; + } + $Time =~ /^(..):(..):(..)$/; + $Finish[$cnt] = ( $1 * 60 + $2 ) * 60 + $3; + $OnLine[$cnt] = $Finish[$cnt] - $Start[$cnt]; + $OnLine[$cnt] += 86400 if(( $Finish[$cnt] - $Start[$cnt] ) < 0 ); + $start = 0; + $cnt++; + } + } + # got another PID! + elsif( $Text =~ /^connect \".+\"/ + || $Text =~ /^inbound (\S+) session/ + || $Text =~ /^outbound (\S+) session/ ) + { + # Possible there was incorrectly terminated session + # due to mailer crash or killing, so getting this string + # can mean that we need to break reading session statistic? + # But we can also get it if log file used not only by one + # mailer at the same time, so.. ignore :) + } + } # end of while( ) + + close(FLOG); + + $TimeLast = "$Mon $Day $Time" if( $Mon && $Day && $Time ); +} + +sub SessionsStatistic +{ + local ($addr, $start, $finish, $online, $ibyte, $obyte, $cps, $speed); + my ($i); + + $~ = HEADER; + write; + $~ = EACH; + + for ($i = 0; $i < $cnt; $i++) + { + $addr = $Address[$i]; + $stat = "$Direction[$i]$Status[$i]$Success[$i]"; + $start = sec2str($Start[$i], "short"); + $finish = sec2str($Finish[$i], "short"); + $online = sec2str($OnLine[$i], "long"); + $ibyte = $InBytes[$i]; + $in = $InFiles[$i]; + $obyte = $OutBytes[$i]; + $on = $OutFiles[$i]; + $cps = int( ($ibyte + $obyte) / $OnLine[$i] ) if ($OnLine[$i] > 0); + $speed = $Connect[$i]; + $ibyte = num2siz( $ibyte ); + $obyte = num2siz( $obyte ); + write; + } + + $~ = FOOTER; + write; +} + +sub TotalStatistic +{ + undef( %hSystems ); + undef( %hCalls ); + undef( %hTimes ); + undef( %hSessions ); + undef( %hInBytes ); + undef( %hOutBytes ); + undef( %hInFiles ); + undef( %hOutFiles ); + local($cal, $ses, $time, $ibyte, $obyte, $inum, $onum, $icps, $ocps); + local($acal, $ases, $atime, $aibyte, $aobyte, $ainum, $aonum, $aicps, $aocps); + local($sys); + my($i); + + $acal = 0; + $ases = 0; + $atime = 0; + $aibyte = 0; + $aobyte = 0; + $ainum = 0; + $aonum = 0; + $aicps = 0; + $aocps = 0; + + for( $i = 0; $i < $cnt; $i++ ) + { + $sys = $Address[$i]; + if( !defined($hSystems{$sys}) ) + { + $hSystems{$sys} = 1; + $hCalls{$sys} = $Calls{$sys}; $Calls{$sys} = 0; + $hTimes{$sys} = 0; + $hSessions{$sys} = 0; + $hInBytes{$sys} = 0; + $hOutBytes{$sys} = 0; + $hInFiles{$sys} = 0; + $hOutFiles{$sys} = 0; + } + $hTimes{$sys} += $OnLine[$i]; + $hSessions{$sys} += 1; + $hInBytes{$sys} += $InBytes[$i]; + $hOutBytes{$sys} += $OutBytes[$i]; + $hInFiles{$sys} += $InFiles[$i]; + $hOutFiles{$sys} += $OutFiles[$i]; + } + @Syst = sort( keys( %hSystems )); + + $~ = hHEADER; + write; + + $~ = hEACH; + for( $i = 0; $i <= $#Syst; $i++ ) + { + $sys = $Syst[$i]; + $cal = ( $hCalls{$sys} || 0 ); $acal += $cal; + $ses = $hSessions{$sys}; $ases += $ses; + $time = sec2str($hTimes{$sys}, "long"); $atime += $hTimes{$sys}; + $ibyte = $hInBytes{$sys}; $aibyte += $ibyte; + $obyte = $hOutBytes{$sys}; $aobyte += $obyte; + $inum = $hInFiles{$sys}; $ainum += $inum; + $onum = $hOutFiles{$sys}; $aonum += $onum; + + if( $hInFiles{$sys} > 0 || $hOutFiles{$sys} > 0 ) + { + $cps = int( ($hInBytes{$sys} + $hOutBytes{$sys}) / $hTimes{$sys} ); + $acps += $cps; + $sess++; + } + else + { + $cps = 0; + } + write; + } + + # Now, draw systems without sessions .. + @Syst = sort( keys( %Calls )); + $ses = "-"; + $time = "-"; + $ibyte = "-"; + $obyte = "-"; + $inum = "-"; + $onum = "-"; + $cps = "-"; + for( $i = 0; $i <= $#Syst; $i++ ) + { + $sys = $Syst[$i]; + if( $Calls{$sys} ) + { + $sys = $Syst[$i]; + $cal = $Calls{$sys}; $acal += $cal; + write; + } + } + $atime = sec2str($atime, "long"); + if( $sess > 0 ) + { + $acps = int( $acps / $sess ); + } + else + { + $acps = 0; + } + + $~ = hFOOTER; + write; +} + +sub num2siz +{ + my($num) = $_[0]; + my($siz); + if($num < 1000) { + $siz = $num.' '; + } elsif($num < 10000000) { + $siz = int($num/1024).'k'; + } else { + $siz = int($num/(1024*1024)).'M'; + } + return $siz; +} + +sub sec2str +{ + my($sec) = $_[0]; + my($tip) = $_[1]; + my ($h, $m, $s); + $h = int( $sec / 3600 ); + $m = int( ($sec - $h*3600) / 60); + $s = int( $sec % 60 ); + if( $tip =~ /short/ ) { + return sprintf("%02d:%02d", $h, $m); + } elsif( $tip =~ /long/ ) { + return sprintf("%03d:%02d:%02d", $h, $m, $s); + } +} + +format HEADER = + ╙■■ Call : 'I' - Incoming, 'O' - Outgoing + ┐╙■ Status : 'U' - Unlisted, 'L' - Listed, 'P' - Protected + ┐┐╙ Session : ' ' - Success, 'A' - Aborted +╔²²²²²²²²²²²║²²²║²²²²²²²²²²²²²²²║²²²²²²²²²║²²²²²²²²²²║²²²²²²²²²²║²²²²²║²²²²²┬ +┐ Time ┐Sta┐ FTN ┐ On-Line ┐ Incoming ┐ Outgoing ┐ Avg.┐Speed┐ +┐hh:mm-hh:mm┐tus┐ Address ┐hhh:mm:ss┐ Bytes┐ N ┐ Bytes┐ N ┐ CPS ┐ ┐ +√²²²²²²²²²²²╗²²²╗²²²²²²²²²²²²²²²╗²²²²²²²²²╗²²²²²²╗²²²╗²²²²²²╗²²²╗²²²²²╗²²²²²┘ +. +format EACH = +┐@<<<<-@<<<<┐@<<┐@<<<<<<<<<<<<<<┐@>>>>>>>>┐@>>>>>┐@>>┐@>>>>>┐@>>┐@>>>>┐@>>>>┐ +$start,$finish,$stat,$addr, $online, $ibyte, $in,$obyte, $on,$cps, $speed +. +format FOOTER = +╓²²²²²²²²²²²÷²²²÷²²²²²²²²²²²²²²²÷²²²²²²²²²÷²²²²²²÷²²²÷²²²²²²÷²²²÷²²²²²÷²²²²²▌ + @>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + $Version +. + +format hHEADER = +╔²²²²²²²²²²²²²²²║²²²²²²²²²║²²²²²²²²²║²²²²²²²²²²²²²²║²²²²²²²²²²²²²²║²²²²²┬ +┐ FTN ┐ Total ┐ Time ┐ Incoming ┐ Outgoing ┐ CPS ┐ +┐ Address ┐Cal.┐Ses.┐ On-Line ┐ Bytes ┐ NN ┐ Bytes ┐ NN ┐ ┐ +√²²²²²²²²²²²²²²²╗²²²²╗²²²²╗²²²²²²²²²╗²²²²²²²²²╗²²²²╗²²²²²²²²²╗²²²²╗²²²²²┘ +. +format hEACH = +┐@<<<<<<<<<<<<<<┐@>>>┐@>>>┐@||||||||┐@>>>>>>>>┐@>>>┐@>>>>>>>>┐@>>>┐@>>>>┐ +$sys, $cal,$ses,$time, $ibyte, $inum,$obyte, $onum,$cps +. +format hFOOTER = +⌠■■■■■■■■■■■■■■■∙■■■■∙■■■■∙■■■■■■■■■∙■■■■■■■■■∙■■■■∙■■■■■■■■■∙■■■■∙■■■■■└ +┐ TOTAL ┐@>>>┐@>>>┐@||||||||┐@>>>>>>>>┐@>>>┐@>>>>>>>>┐@>>>┐@>>>>┐ + $acal,$ases,$atime, $aibyte, $ainum,$aobyte,$aonum,$acps +╓²²²²²²²²²²²²²²²÷²²²²÷²²²²÷²²²²²²²²²÷²²²²²²²²²÷²²²²÷²²²²²²²²²÷²²²²÷²²²²²▌ + @>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + $Version +. diff --git a/contrib/callout.sh b/contrib/callout.sh new file mode 100644 index 0000000..006c468 --- /dev/null +++ b/contrib/callout.sh @@ -0,0 +1,229 @@ +#!/bin/sh + +Ver=1.1h + +# Скрипт для прозвонки на аплинков +# Про время их работы (и телефоны хидденов) должен знать мейлер +# +# Заточен для мейлера BinkleyForce +# Для других править функцию docallout + +# +# Copyright (c) 2000 by Georgi Fofanov, 2:5050/29@fidonet +# +# 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. +# + +# Путь к outbound'у нужной зоны (пока знаем только про одну зону) +outb=/var/spool/ifmail/outb/ + +# Путь к каталогу с lock-файлами (последний слэш нужен!) +lock=/var/lock/ + +# Пауза между звонками +# В секундах +dialdelay=120 + +# Период сканирования outbound'а +# Пока после завершения круга прозвонки будет 2 паузы - dialdelay и scan +# В секундах +scan=60 + +# Пауза между проверками lock-файла +# В секундах +lockdelay=10 + +# Расположение мейлера +mailer=/usr/local/bin/bforce + +# Команда, выполняемая после успешной сессии +after=/usr/local/bin/after_session + +# Устройство, на котором сидит модем +TTY="ttyS1" + +# Здесь перечислены системы, на которые можно звонить и (через пробел) число +# их модемных линий +# Например: +# 2:5050/13 3 +# 2:5050/9 2 +# 2:5050/33 1 +sys_poll=/etc/fido/poll.list + +# Пользователь, от имени которого надо запускать +mailer_owner=fido + +# Временный файл, куда записывается список ?lo и ?ut +list_file=/var/spool/ifmail/list.lst + +# Временный файл +tmp_file=/var/spool/ifmail/list.tmp + +# Временный файл, в котором перечислены системы, на которые будем звонить +poll_file=/var/spool/ifmail/polling.list + +# Максимальное число попыток дозвониться на систему +MAXTRY=25 + +# Сколько времени не звонить на систему, если исчерпано число попыток дозвона +# В минутах +MAXTIME=60 + +# Производим звонок +function docallout () +{ + local zone=$1 net=$2 node=$3 point=$4 curtry=$5 numline=$6 line + + let line=${curtry}%${numline} + + if [ $point = 0 ] ; then + echo -n `date +%b\ %m\ %T` callout[$$] Звоним на ${zone}:${net}/${node} \(try \#${curtry}\) + $mailer ${zone}:${net}/${node} -l $line + let result=$? + else + echo -n `date +%b\ %m.%Y\ %T` callout[$$] Звоним на ${zone}:${net}/${node}.${point} \(try \#${curtry}\) + $mailer ${zone}:${net}/${node}.${point} -l $line + let result=$? + fi + + case $result in + 0 ) echo " успешно" ;; + * ) echo " ошибка" \#$result ;; + esac + + if [ $result = 0 ] ; then + echo `date +%s` 0 0 >$sts + `$after` + else + echo `date +%s` $curtry $result >$sts + fi +} + +# Проверяем, можно ли звонить на эту систему +function checkcallout () +{ + local curtry=$1 zone=$2 net=$3 node=$4 point=$5 numline=0 + + if [ $point = 0 ] ; then + `fgrep "${zone}:${net}/${node}" $sys_poll | awk '{ print "let numline=" $2 }'` + else + `fgrep "${zone}:${net}/${node}.${point}" $sys_poll | awk '{ print "let numline=" $2 }'` + fi + if [ $numline == 0 ] ; then return ; fi + + docallout $zone $net $node $point $curtry $numline +} + +# Сканируем outbound +function scandir () +{ + find -type f -and \( -name "*.?lo" -o -name "*.?ut" \) > $list_file + for file in `cat $list_file` ; do + eval `echo $file | awk '{ sub(/\.\//, "") + if (substr($0, 9, 4) == ".pnt") { + point = substr($0, 18, 4) + } else { + point = 0 + } + printf "zonehex=%s nethex=%s nodehex=%s pointhex=%s let zone=0x%s net=0x%s node=0x%s point=0x%s", + "2", substr($0, 1, 4), substr($0, 5, 4), point, + "2", substr($0, 1, 4), substr($0, 5, 4), point + }'` + ext=${file:${#file}-3} + sts=${file%%?ut} + sts=${sts%%?lo} + bsy=${sts}bsy + sts=${sts}sts + if [ $ext != hlo -a $ext != hut ] ; then + echo ${zone} ${net} ${node} ${point} $sts $bsy >> $tmp_file + fi + done + + rm $list_file + + if [ -f $tmp_file ] ; then + `cat $tmp_file | sort | uniq > $poll_file` + rm $tmp_file + n=0 + for sys in `cat $poll_file` ; do + let n=${n}+1 + let tmp=${n}%6 + case $tmp in + 1 ) let zone=$sys ;; + 2 ) let net=$sys ;; + 3 ) let node=$sys ;; + 4 ) let point=$sys ;; + 5 ) sts=$sys ;; + 0 ) bsy=$sys ;; + esac + if [ $tmp == 0 ] ; then + while [ -e ${lock}LCK..$TTY ] + do + sleep $lockdelay + done + if [ ! -f $bsy ] ; then + if [ ! -f $sts ] ; then + let lasttime=0 retries=0 errcode=0 + else + `cat $sts|awk '{ print "let lasttime=" $1 " retries=" $2 " errcode=" $3 }'` + fi + let curtime=`date +%s` + let timediff=${curtime}-${lasttime} + let curtry=${retries}+1 + if [ $curtry -gt $MAXTRY ] ; then + if [ $timediff -gt $MAXTIME ] ; then + let curtry=1 + checkcallout $curtry $zone $net $node $point + sleep $dialdelay + fi + else + checkcallout $curtry $zone $net $node $point + sleep $dialdelay + fi + fi + fi + done + rm $poll_file + fi + +} + +function main () +{ + + cd $outb + + while [ ! -f /tmp/callout.exit ] ; do + if [ ! -e ${lock}LCK..$TTY ]; then + scandir + sleep $scan + else + sleep $lockdelay + fi + done + rm /tmp/callout.exit +} + +if [ `whoami` != "$mailer_owner" ]; then + echo "wrong uid, run as user $mailer_owner (rc=2)" + exit 2 +fi + +. /etc/profile > /dev/null 2>&1 +let MAXTIME=${MAXTIME}*60 +main >> /var/log/ifmail/callout.log 2>&1 + +## Изменения + +# Ver 1.1, 09 Jul 2000: +# +# Обнуление числа попыток после успешной сессии +# +# Не работал MAXTIME + +# Ver 1.0, 08 Jul 2000: +# +# Первая стабильная версия diff --git a/contrib/init.d/bforce b/contrib/init.d/bforce new file mode 100644 index 0000000..e2905f9 --- /dev/null +++ b/contrib/init.d/bforce @@ -0,0 +1,51 @@ +#!/bin/sh +# +# bforce FTN mailer +# +# chkconfig: 345 94 14 +# description: Starts and stops the binkleyforce mailer daemon +# +# 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. + +OWNER=uucp +BFORCE=/usr/local/fido/bin/bforce + +# Source function library. +. /etc/init.d/functions + +[ -f $BFORCE ] || exit 0 + +# See how we were called. +case "$1" in + start) + # Start daemon. + echo -n "Starting bforce: " + su $OWNER -c ". /etc/rc.d/init.d/functions; daemon $BFORCE -d" + echo + touch /var/lock/subsys/bforce + ;; + stop) + # Stop daemon. + echo -n "Shutting down bforce: " + killproc bforce + rm -f /var/lock/subsys/bforce + echo + ;; + status) + status bforce + exit $? + ;; + restart) + $0 stop + $0 start + exit $? + ;; + *) + echo "Usage: bforce {start|stop|status|restart}" + exit 1 +esac + +exit 0 diff --git a/contrib/init.d/bforce.debian b/contrib/init.d/bforce.debian new file mode 100644 index 0000000..b918c03 --- /dev/null +++ b/contrib/init.d/bforce.debian @@ -0,0 +1,44 @@ +#!/bin/sh +# +# bforce FTN mailer +# +# chkconfig: 345 94 14 +# description: Starts and stops the binkleyforce mailer daemon +# +# 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. + +OWNER=uucp +BFORCE=/usr/local/fido/bin/bforce + +[ -f $BFORCE ] || exit 0 + +# See how we were called. +case "$1" in + start) + # Start daemon. + echo -n "Starting bforce. " + su $OWNER -c "daemon $BFORCE -d" + echo + touch /var/lock/subsys/bforce + ;; + stop) + # Stop daemon. + echo -n "Shutting down bforce. " + $BFORCE -q + rm -f /var/lock/subsys/bforce + echo + ;; + restart) + $0 stop + $0 start + exit $? + ;; + *) + echo "Usage: bforce {start|stop|restart}" + exit 1 +esac + +exit 0 diff --git a/contrib/outman b/contrib/outman new file mode 100644 index 0000000..49b4eb1 --- /dev/null +++ b/contrib/outman @@ -0,0 +1,366 @@ +#!/usr/bin/tclsh +# +# Copyright (c) 2000 by Alexander Belkin +# +# $Id$ +# +# Tcl script for creating polls, file requests and file attaches +# +# 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. + +################## +# Program settings + +# Defaults for address completion +set def_zone 2 +set def_net 5020 +set def_node 1398 + +# Path to your main BSO directory (not implemented) +#set bso_dir "/var/spool/ftn/out" + +# Path to your ASO directory +set aso_dir "/var/spool/fido/amiga.out" + +# Log file name +set logfile "/var/log/bforce/outman.log" + +# Uncomment this if you not need logging +#set logfile {} + +################################ +# The program's body starts here + +set LOG {} + +proc stupid_user {} { + + puts "Usage: outman <\[poll|freq|send]> \[options]
\[files]\n" + puts "options:" + puts " -hold set hold flavor" + puts " -normal set normal flavor (default)" + puts " -crash set crash flavor" + puts " -kill kill files after send" + puts " -truncate truncate files after send" + puts "" + puts "Mail bug reports to " + exit 1 +} + +proc log {str} { + + global LOG + global logfile + + if { $logfile != {} } { + + if { $LOG == {} } { + set LOG [open $logfile "a"] + } + + set seconds [clock seconds] + + puts $LOG "[clock format $seconds -format "%d/%m %H:%M:%S"] $str" + + } +} + +proc parse_addr {str} { + + global def_zone + global def_net + global def_node + set zone $def_zone + set net $def_net + set node $def_node + set point 0 + + if { [regexp "^\[0-9]+:\[0-9]+/\[0-9]+\\.?\[0-9]*$" $str] } { + + regexp "(\[0-9]+):(\[0-9]+)/(\[0-9]+)\\.?(\[0-9]*)$" $str \ + {} zone net node point + + } elseif { [regexp "^\[0-9]+/\[0-9]+\\.?\[0-9]*$" $str] } { + + regexp "(\[0-9]+)/(\[0-9]+)\\.?(\[0-9]*)$" $str \ + {} net node point + + } elseif { [regexp "^\[0-9]+\\.?\[0-9]*$" $str] } { + + regexp "^(\[0-9]*)\\.?(\[0-9]*)$" $str \ + {} node point + + } elseif { [regexp "^\.\[0-9]+$" $str] } { + + regexp "^\.(\[0-9]+)$" $str \ + {} point + + } else { + + puts "invalid address $str" + return {} + + } + + if { $zone == {} } { set zone [$def_zone] } + if { $net == {} } { set net [$def_net] } + if { $node == {} } { set node [$def_node] } + if { $point == {} } { set point 0 } + + # puts "debug: address parse '$str' -> '$zone,$net,$node,$point'" + + return "$zone $net $node $point" +} + +proc addrstr {addr} { + + return [lindex $addr 0]:[lindex $addr 1]/[lindex $addr 2].[lindex $addr 3] +} + +# +# TODO: support for outbounds not in the default zone +# +proc filename_bso {addr flavor} { + + global bso_dir + + set zone [lindex $addr 0] + set net [lindex $addr 1] + set node [lindex $addr 2] + set point [lindex $addr 3] + + if { $point } { + + set name [format "%04x%04x.pnt/%08x" $net $node $point] + + } else { + + set name [format "%04x%04x" $net $node] + + } + + switch $flavor { + "bsy" { + return "$bso_dir/$name.bsy" + } + "freq" { + return "$bso_dir/$name.req" + } + "hold" { + return "$bso_dir/$name.hlo" + } + "crash" { + return "$bso_dir/$name.clo" + } + default { + return "$bso_dir/$name.flo" + } + } +} + +proc filename_aso {addr flavor} { + + global aso_dir + + set name [lindex $addr 0].[lindex $addr 1].[lindex $addr 2].[lindex $addr 3] + + switch $flavor { + "bsy" { + return "$aso_dir/$name.bsy" + } + "freq" { + return "$aso_dir/$name.req" + } + "hold" { + return "$aso_dir/$name.hlo" + } + "crash" { + return "$aso_dir/$name.clo" + } + default { + return "$aso_dir/$name.flo" + } + } +} + +proc bsy_exist {addr} { + + set bsyname [filename_aso $addr "bsy"] + + if { [file exists $bsyname] } { + return 1 + } + + return 0 +} + +proc command_freq {addr files} { + + set reqname [filename_aso $addr "freq"] + set name {} + + # puts "debug: file request name is '$reqname'" + + set REQ [open $reqname "a"] + + foreach name $files { + puts $REQ $name + log "request \"$name\" from [addrstr $addr]" + } + + close $REQ +} + +proc command_poll {addr flavor} { + + set floname [filename_aso $addr $flavor] + + if { ![file exists $floname] } { + + set FLO [open $floname "a"] + close $FLO + log "poll [addrstr $addr] ($flavor)" + + } else { + + log "cannot create poll for [addrstr $addr]: allready polled" + } +} + +proc command_send {addr files flavor action} { + + set floname [filename_aso $addr $flavor] + set name {} + set curdir [exec pwd] + + set FLO [open $floname "a"] + + foreach name $files { + if { [file exists $name] } { + + if { [file pathtype $name] == "relative" } { + if { [string match "./*" $name] } { + set name [string range $name 2 end] + } + set name "$curdir/$name" + } + + log "send file \"$name\" ([file size $name] bytes) to [addrstr $addr] ($flavor)" + + switch $action { + "kill" { + puts $FLO "^$name" + } + "truncate" { + puts $FLO "#$name" + } + default { + puts $FLO "@$name" + } + } + + } else { + + puts "skip file \"$name\" to [addrstr $addr]: file not exist" + + } + } + + close $FLO +} + +############################## +# The main program starts here + +if { $argc < 2 } { + stupid_user +} + +set command {} +set address {} +set addr {} +set files {} +set flavor "normal" +set action "nothing" + +for {set i 0} {$i < $argc} {incr i} { + + set arg [lindex $argv $i] + + if { [string index $arg 0] == "-" } { + + switch [string range $arg 1 end] { + "hold" { + set flavor "hold" + } + "normal" { + set flavor "normal" + } + "crash" { + set flavor "crash" + } + "kill" { + set action "kill" + } + "truncate" { + set action "truncate" + } + default { + puts "unknown command line option '$arg'" + stupid_user + } + } + + } elseif { $command == {} } { + + set command $arg + + } elseif { $address == {} } { + + set address $arg + set addr [parse_addr $address] + if { $addr == {} } { + stupid_user + } + + } else { + + lappend files $arg + + } +} + +if { $command == {} || $address == {} } { + stupid_user +} + +if { [bsy_exist $addr] } { + puts "bsy file exist for address [addrstr $addr]" + exit 2 +} + +switch $command { + "poll" { + command_poll $addr $flavor + } + "freq" { + command_freq $addr $files + } + "send" { + command_send $addr $files $flavor $action + } + default { + puts "unknown command $command" + stupid_user + } +} + +if { $LOG != {} } { + close $LOG +} + +exit 0 + diff --git a/contrib/timesync.tcl b/contrib/timesync.tcl new file mode 100644 index 0000000..6c22651 --- /dev/null +++ b/contrib/timesync.tcl @@ -0,0 +1,116 @@ +#!/usr/bin/tclsh +# +# Copyright (c) 2000 by Alexander Belkin +# +# $Id$ +# +# Time syncronization utility +# +# 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. + +################## +# Program settings + +set bforce_log_file "/var/log/bforce/bf-log.ttyS0" +set sync_with_addr "2:450/102" +set max_time_diff 1800 +set min_time_diff 20 +set news_groups "local.robots" +set from_user "Time Robot " +set inews_cmd "/usr/bin/inews" + +################################ +# The program's body starts here + +set sess_pid "" +set remote_times "" +set local_times "" +set TEXT "" + +set INP [open $bforce_log_file "r"] +foreach line [split [read $INP] "\n"] { + + set fields [split $line " "] + set pid [lindex $fields 3] + set time [join [lrange $fields 0 2]] + set data [join [lrange $fields 4 end]] + + if { [string match "*Address : $sync_with_addr" $data] } { + set sess_pid $pid + set sess_time "" + } elseif { [string match "*Time :*" $data] } { + if { $sess_pid == $pid } { + regexp "Time : (.+)" $data {} timestr + if { $timestr != "" } { + set sess_time $timestr + } + } + } elseif { [string match "remote is*,protected" $data] } { + if { $sess_pid == $pid } { + if { $sess_time != "" && $time != "" } { + lappend remote_times $sess_time + lappend local_times $time + } + set sess_pid "" + set sess_time "" + } + } elseif { [string match "remote is*" $data] } { + if { $sess_pid == $pid } { + set sess_pid "" + set sess_time "" + } + } + +} +close $INP + +set last_rem_time [lindex $remote_times end] +set last_loc_time [lindex $local_times end] + +if { $last_rem_time != "" && $last_loc_time != "" } { + + regexp "(\[0-9]+):(\[0-9]+):(\[0-9]+)" $last_rem_time {} rh rm rs + regexp "(\[0-9]+):(\[0-9]+):(\[0-9]+)" $last_loc_time {} lh lm ls + set rem [expr "$rh*3600 + $rm*60 + $rs"] + set loc [expr "$lh*3600 + $lm*60 + $ls"] + set diff [expr "$rem - $loc"] + + if { [expr abs($diff)] < $min_time_diff } { + # Do nothing + } elseif { [expr abs($diff)] <= $max_time_diff } { + set old_sec [clock seconds] + set new_sec [expr $old_sec + $diff] + + exec /bin/date -s [clock format $new_sec -format "%d-%b-%Y %H:%M:%S"] + exec /sbin/clock -wu + + append TEXT "The System time was synchronized with the node $sync_with_addr\n\n" + append TEXT "Old time : [clock format $old_sec]\n" + append TEXT "New time : [clock format $new_sec]\n" + append TEXT "Time difference : $diff second(s)\n" + } else { + set old_sec [clock seconds] + set new_sec [expr $old_sec + $diff] + + append TEXT "The System time WAS NOT synchronized with the node $sync_with_addr\n\n" + append TEXT "Current time : [clock format $old_sec]\n" + append TEXT "Want set time : [clock format $new_sec]\n" + append TEXT "Time difference : $diff second(s) (must be lower $max_time_diff seconds)\n" + } +} + +if { $TEXT != "" } { + + set MSG "From: $from_user\n" + append MSG "Subject: Time synchronization\n" + append MSG "Newsgroups: $news_groups\n\n" + append MSG $TEXT + + exec $inews_cmd -h << $MSG +} + +exit 0 + diff --git a/contrib/u-srif/INFO b/contrib/u-srif/INFO new file mode 100644 index 0000000..460f636 --- /dev/null +++ b/contrib/u-srif/INFO @@ -0,0 +1,6 @@ +License notice for u-srif-py + +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. diff --git a/contrib/u-srif/conf/report.footer b/contrib/u-srif/conf/report.footer new file mode 100644 index 0000000..3893b35 --- /dev/null +++ b/contrib/u-srif/conf/report.footer @@ -0,0 +1,27 @@ + ++-----------+----------------------+----------------------+ +| | Statistic | Limits | +| Period +-------------+--------+-------------+--------+ +| | Size | Number | Size | Number | ++-----------+-------------+--------+-------------+--------+ +| Day | @%-11d,sent_day_size@ | @%-6d,sent_day_num@ | @%-11s,limit_size_day@ | @%-6s,limit_num_day@ | ++-----------+-------------+--------+-------------+--------+ +| Week | @%-11d,sent_week_size@ | @%-6d,sent_week_num@ | @%-11s,limit_size_week@ | @%-6s,limit_num_week@ | ++-----------+-------------+--------+-------------+--------+ +| Month | @%-11d,sent_month_size@ | @%-6d,sent_month_num@ | @%-11s,limit_size_month@ | @%-6s,limit_num_month@ | ++-----------+-------------+--------+-------------+--------+ +| Total | @%-11d,sent_total_size@ | @%-6d,sent_total_num@ | ++-----------+-------------+--------+ + +****************************************************************************** +File requests policy +****************************************************************************** + +File requests supported at 00:00-05:30 and at least 9600 speed + +There are aliases for file requests: + +FILES - Happy Station files list +BFORCE - The latest version of the binkleyforce mailer + +Bye, call again! diff --git a/contrib/u-srif/conf/report.header b/contrib/u-srif/conf/report.header new file mode 100644 index 0000000..8371b19 --- /dev/null +++ b/contrib/u-srif/conf/report.header @@ -0,0 +1,2 @@ +Hello, @%s,remote_sysop@! + diff --git a/contrib/u-srif/conf/u-srif.aliases b/contrib/u-srif/conf/u-srif.aliases new file mode 100644 index 0000000..94e63d2 --- /dev/null +++ b/contrib/u-srif/conf/u-srif.aliases @@ -0,0 +1,6 @@ + +files /home/ftp/pub/info/happy.zip +filelist /home/ftp/pub/info/happy.lst +test /home/ftp/pub/fileecho/PNT5020/pnt5020.zip +bforce /home/ftp/pub/bforce/bforce-last.tar.gz + diff --git a/contrib/u-srif/conf/u-srif.conf b/contrib/u-srif/conf/u-srif.conf new file mode 100644 index 0000000..09f05e5 --- /dev/null +++ b/contrib/u-srif/conf/u-srif.conf @@ -0,0 +1,21 @@ +############################################################################## +### u-srif FREQ processor configuration file ################################# +############################################################################## + +# Spool directory for files index, links statistic, etc. +spool-dir /var/spool/u-srif + +# Log file name +log-file /var/log/ftn/u-srif.log + +# File with list of freqable directories +dir-list-file /usr/local/etc/u-srif/u-srif.dirs + +# File with list of freqable directories +alias-list-file /usr/local/etc/u-srif/u-srif.aliases + +freq-policy /usr/local/etc/u-srif/policy.text + +freq-magic bforce-cvs /usr/local/etc/u-srif/magic/bforce-cvs +freq-alias = files /home/ftp/pub password + diff --git a/contrib/u-srif/conf/u-srif.dirs b/contrib/u-srif/conf/u-srif.dirs new file mode 100644 index 0000000..c65c6c7 --- /dev/null +++ b/contrib/u-srif/conf/u-srif.dirs @@ -0,0 +1,42 @@ +/home/ftp/pub/bforce/ +/home/ftp/pub/fileecho/ADV_FTNSOFT/ +/home/ftp/pub/fileecho/AFTNMISC/ +/home/ftp/pub/fileecho/AVP/ +/home/ftp/pub/fileecho/BOOK/ +/home/ftp/pub/fileecho/CRACKER/ +/home/ftp/pub/fileecho/CRACKS/ +/home/ftp/pub/fileecho/FAR/ +/home/ftp/pub/fileecho/FR_CO.FILES/ +/home/ftp/pub/fileecho/FWUTILS/ +/home/ftp/pub/fileecho/GSS_BETA/ +/home/ftp/pub/fileecho/GSS_SOFT/ +/home/ftp/pub/fileecho/G_CHEAT/ +/home/ftp/pub/fileecho/IT.FILES/ +/home/ftp/pub/fileecho/IT.MP3/ +/home/ftp/pub/fileecho/IT.MUSIC/ +/home/ftp/pub/fileecho/IT.NDL/ +/home/ftp/pub/fileecho/LARRY.FILES/ +/home/ftp/pub/fileecho/HAPPY.XCK/ +/home/ftp/pub/fileecho/MOBIL/ +/home/ftp/pub/fileecho/NET5020/ +/home/ftp/pub/fileecho/PNT5020/ +/home/ftp/pub/fileecho/RUFO/ +/home/ftp/pub/fileecho/STICK.FILES/ +/home/ftp/pub/fileecho/T-MAIL/ +/home/ftp/pub/fileecho/UNKNOWN/ +/home/ftp/pub/fileecho/XDOCREF/ +/home/ftp/pub/fileecho/XGAMSOL/ +/home/ftp/pub/fileecho/XHAMRADIO/ +/home/ftp/pub/fileecho/XHRDASUS/ +/home/ftp/pub/fileecho/XHRDDOCS/ +/home/ftp/pub/fileecho/XHRDIDC/ +/home/ftp/pub/fileecho/XHRDUSR/ +/home/ftp/pub/fileecho/XPICART/ +/home/ftp/pub/fileecho/XPICHUMOR/ +/home/ftp/pub/fileecho/XPICMUSIC/ +/home/ftp/pub/fileecho/XPICSHIP/ +/home/ftp/pub/fileecho/XPICSYSOP/ +/home/ftp/pub/fileecho/XPICWEAPON/ +/home/ftp/pub/files/uue_files/ +/home/ftp/pub/redhat-5.2/RedHat/RPMS/ +/home/ftp/pub/redhat-6.1/RedHat/RPMS/ diff --git a/contrib/u-srif/lib/uconfig.py b/contrib/u-srif/lib/uconfig.py new file mode 100644 index 0000000..e9447f3 --- /dev/null +++ b/contrib/u-srif/lib/uconfig.py @@ -0,0 +1,163 @@ + +import gdbm +import string +import os +import ufido + +ALIAS_TYPE_NORMAL = 1 # Traditional aliase +ALIAS_TYPE_MAGIC = 2 # "Magic" alias + +# TODO: These functions must generate an exception in case of errors +def get_bool(str): + str = string.lower(str) + if str == 'yes' or str == 'true': + return 1 + elif str == 'no' or str == 'false': + return 0 + return None + +def get_size(str): + # TODO: support nice size formats like 64M, 10G + return str + +def get_alias(str, type): + args = string.split(str) + if len(args) < 2 or len(args) > 3: + return None + if len(args) == 3: + passwd = args[2] + else: + passwd = None + return Alias(args[0], args[1], passwd, type) + +class Alias: + """ Aliases implementation + """ + def __init__(self, name, filename, passwd, type): + """ Alias initialisation + """ + self.name = name + self.filename = filename + self.type = type + + def get(self, passwd): + """ Get the list of files to send for this alias + """ + yield = [] + if self.type == ALIAS_TYPE_NORMAL: + yield.append(self.filename) + return yield + elif self.type == ALIAS_TYPE_MAGIC: + # Prepare the environment (TODO) + putenv('PASSWORD', passwd) + putenv('ADDRESS', None) + putenv('PROTECTED', 'FALSE') + putenv('LISTED', 'FALSE') + # Execute magic program and process its output + try: + magic = popen(self.filename) + line = magic.readline() + while line: + line = magic.readline() + yield.append(string.strip(line)) + if magic.close(): + print "Magic return code is non-zero: ", self.filename + return None + return yield + except IOError: + print "Failed to run magic: ", self.filename + return None + +class Config: + def read_dir_list(self): + yield = [] + fp = open(self.dir_list_file, 'r') + line = fp.readline() + while line: + line = string.strip(line) + if line != '': + yield.append(line) + line = fp.readline() + fp.close() + return yield + + def read_alias_list(self): + yield = [] + fp = open(self.alias_list_file, 'r') + line = fp.readline() + while line: + line = string.strip(line) + if line != '': + [name, filename] = string.split(line, None, 1) + yield.append(alias(name, filename)) + line = fp.readline() + fp.close() + return yield + + def read(self, name): + fp = open(name, 'r') + line = fp.readline() + while line: + line = string.strip(line) + args = string.split(line, None, 1) + if line[0:1] == '#' or len(line) == 0: + pass + elif len(args) != 2: + print "Invalid string in config: ", line + else: + key = string.lower(args[0]) + val = args[1] + if key == 'dir-list-file': + self.dir_list_file = val + elif key == 'send-report': + self.send_report = get_bool(val) + elif key == 'limit-size-day': + self.limit_size_day = get_size(val) + elif key == 'limit-size-week': + self.limit_size_week = get_size(val) + elif key == 'limit-size-month': + self.limit_size_month = get_size(val) + elif key == 'spool-dir': + self.spool_dir = val + elif key == 'freq-alias': + self.freq_alias.append(get_alias(val, ALIAS_TYPE_NORMAL)) + elif key == 'freq-magic': + self.freq_magic.append(get_alias(val, ALIAS_TYPE_MAGIC)) + elif key == 'log-file': + self.log_file = val + elif key == 'local-address': + self.local_address.parse(var) + elif key == 'report-header': + self.report_header = val + elif key == 'report-footer': + self.report_footer = val + elif key == 'report-from': + self.report_from = val + elif key == 'report-subj': + self.report_subj = val + elif key == 'stat-dbase': + self.stat_dbase = val + else: + print "unknown config keyword:", key + line = fp.readline() + fp.close() + + def __init__(self, name): + self.dir_list_file = '' + self.send_report = 0 + self.limit_size_day = 0 + self.limit_size_week = 0 + self.limit_size_month = 0 + self.spool_dir = '' + self.freq_policy = '' + self.freq_alias = [] + self.freq_magic = [] + self.log_file = '' + self.local_address = ufido.address() + self.report_header = '' + self.report_footer = '' + self.report_from = 'FREQ manager' + self.report_subj = 'FREQ report' + self.stat_dbase = None + self.read(name) + diff --git a/contrib/u-srif/lib/udbase.py b/contrib/u-srif/lib/udbase.py new file mode 100644 index 0000000..3667712 --- /dev/null +++ b/contrib/u-srif/lib/udbase.py @@ -0,0 +1,151 @@ + +import os +import gdbm +import string + +def get_file_desc(filename): + path, name = os.path.split(filename) + descname = os.path.join(path, '.desc', name + '.desc') + if not os.path.isfile(descname): + return None + try: + fp = open(descname, 'r') + except IOError: + print 'Cannot open', descname + return None + line = fp.readline() + yield = '' + while line: + yield = yield + line + line = fp.readline() + fp.close() + return string.strip(yield) + +def get_area_desc(areapath): + descname = os.path.join(areapath, '.desc', '.desc') + if not os.path.isfile(descname): + return None + try: + fp = open(descname, 'r') + except IOError: + print 'Cannot open', descname + return None + line = fp.readline() + yield = '' + while line: + yield = yield + line + line = fp.readline() + fp.close() + return string.strip(yield) + +class file: + def stat(self): + if self.fake: + return + try: + statinfo = os.stat(self.fullname) + self.size = statinfo[6] + self.time = statinfo[8] + except OSError: + self.size = -1 + self.time = -1 + self.desc = 'File is not accessable' + + def set(self, fullname, name = None, area = '', dlcnt = 0,\ + mode = '', desc = '', fake = 0): + if name == None: + self.name = os.path.split(fullname)[1] + else: + self.name = name + self.fullname = fullname + self.dlcnt = dlcnt + self.size = -1 + self.time = -1 + self.area = area + self.mode = mode + self.desc = desc + self.fake = fake + + def reset(self): + self.name = '' + self.fullname = '' + self.area = '' + self.dlcnt = 0 + self.mode = '' + self.desc = '' + self.size = -1 + self.time = -1 + self.fake = 0 + + def __init__(self): + self.reset() + +class filebase: + """ Index entry format: [fullname, area, dlcnt, accessmode, desc] + """ + def open(self, mode): + self.db = gdbm.open(self.dbfile, mode) + + def close(self): + self.db.close() + + def sync(self): + self.db.sync() + + def clean(self): + for filename in self.db.keys(): + file = self.get(filename) + if not os.path.isfile(file.fullname): + print 'Remove file "%s" from index' % file.fullname + del self.db[filename] + + def get_all(self, filenames): + """ Lookup files in the database and return list + of file objects + """ + yield = [] + for name in filenames: + files = self.get(name) + if files and len(files) > 0: + yield.extend(files) + return yield + + def get(self, filename): + """ Lookup file by its name in the database and + return list of file objects for this name + """ + yield = [] + if not self.db.has_key(filename): + return None + files_info = eval(self.db[filename]) + if files_info == None: + newfile = file() + newfile.set(filename, desc='File not found', fake=1) + yield.append(newfile) + else: + for finfo in files_info: + newfile = file() + finfo = eval(finfo) + newfile.set(finfo[0], area = finfo[1],\ + dlcnt = finfo[2], mode = finfo[3],\ + desc = finfo[4]) + yield.append(newfile) + return yield + + def put(self, file): + finfo = [] + finfo.append(file.fullname) + finfo.append(file.area) + finfo.append(file.dlcnt) + finfo.append(file.mode) + finfo.append(file.desc) + if self.db.has_key(file.name): + files_info = eval(self.db[file.name]) + else: + files_info = [] + files_info.append(repr(finfo)) + self.db[file.name] = repr(files_info) + + def __init__(self, spooldir): + self.dbfile = os.path.join(spooldir, 'filebase.db') + diff --git a/contrib/u-srif/lib/ufido.py b/contrib/u-srif/lib/ufido.py new file mode 100644 index 0000000..31f48c7 --- /dev/null +++ b/contrib/u-srif/lib/ufido.py @@ -0,0 +1,181 @@ + +import string +import re +import struct +import time + +#address_1 = re.compile('^\([0-9]+\):\([0-9]+\)/\([0-9]+\)\.?\([0-9]+\)?$') +address_1 = re.compile('^(\d+):(\d+)/(\d+)\.?(\d+)?$') + +months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\ + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Jan') + +class address: + def is_set(self): + if self.zone > 0 and self.net > 0: + return 1 + return 0 + + def string(self): + if self.invalid: + yield = 'Invalid address' + elif self.point > 0: + yield = '%d:%d/%d.%d' % (self.zone, self.net, self.node, self.point) + else: + yield = '%d:%d/%d' % (self.zone, self.net, self.node) + return yield + + def parse(self, str): + match = address_1.match(str) + if match: + try: + self.zone = string.atoi(match.group(1)) + self.net = string.atoi(match.group(2)) + self.node = string.atoi(match.group(3)) + tmp = match.group(4) + if tmp and tmp != '-1': + self.point = string.atoi(tmp) + else: + self.point = 0 + self.invalid = 0 + except IndexError: + self.__init__() + return -1 + else: + print "Regexp doesnt match!" + return -1 + return 0 + + def __init__(self): + self.zone = 0 + self.net = 0 + self.node = 0 + self.point = 0 + self.invalid = 1 + +class message: + def newmsg(self, addr_from, user_from, addr_to, user_to, subject): + self.unix_time = time.time() + self.addr_orig = addr_from + self.addr_dest = addr_to + self.user_orig = user_from + self.user_dest = user_to + self.subject = subject + self.msgbody = '' + self.append_line('\001FMPT %d' % self.addr_orig.point) + self.append_line('\001TOPT %d' % self.addr_dest.point) + + def append_line(self, string): + self.msgbody = self.msgbody + string + '\r' + + def append_text(self, text): + for line in string.split(text, '\n'): + self.append_line(line) + + def append_file(self, filename): + try: + fp = open(filename, 'r') + except IOError: + print 'Cannot append file', filename + return + line = fp.readline() + while line: + self.append_line(string.rstrip(line)) + line = fp.readline() + fp.close() + + def __init__(self): + self.unix_time = 0 + self.addr_orig = address() + self.addr_dest = address() + self.user_orig = '' + self.user_dest = '' + self.subject = '' + self.msgbody = '' + self.origin = '' + +class packet: + def reset(self): + self.addr_orig = address() + self.addr_dest = address() + self.password = '' + self.messages = [] + + # TODO + def read(self, filename): + self.reset() + fp = open(filename, "w") + fp.close() + + def get_time_string(self, unix_time): + msgtime = time.localtime(unix_time) + return '%02d %s %02d %02d:%02d:%02d' % \ + (msgtime[2], months[msgtime[1]], msgtime[0] % 100, \ + msgtime[3], msgtime[4], msgtime[5]) + + def get_message_header(self, message): + return struct.pack('7H20s',\ + 2,\ + message.addr_orig.node,\ + message.addr_dest.node,\ + message.addr_orig.net,\ + message.addr_dest.net,\ + 0,\ + 0,\ + self.get_time_string(message.unix_time)) + \ + message.user_dest[0:36] + '\0' + \ + message.user_orig[0:36] + '\0' + \ + message.subject[0:72] + '\0' + + def get_packet_header(self): + now = time.localtime(time.time()) + return struct.pack('13H8s12H',\ + self.addr_orig.node,\ + self.addr_dest.node,\ + now[0], # Year\ + now[1], # Month\ + now[2], # Day\ + now[3], # Hour\ + now[4], # Minute\ + now[5], # Second\ + 9600, # Baud\ + 2, # PKT type\ + self.addr_orig.net,\ + self.addr_dest.net,\ + 254, # Prod. code + Rev. number\ + self.password,\ + self.addr_orig.zone,\ + self.addr_dest.zone,\ + 0, # AuxNet\ + 0, # CWvalidationCopy\ + 0, # ProductCode + Revision \ + 0, # CapabilWord\ + self.addr_orig.zone,\ + self.addr_dest.zone,\ + self.addr_orig.point,\ + self.addr_dest.point,\ + 0, + 0) + + def write(self, filename): + fp = open(filename, "w") + fp.write(self.get_packet_header()) + + for msg in self.messages: + fp.write(self.get_message_header(msg)) + fp.write(msg.msgbody) + fp.write('\0') + + fp.write('\0\0') + fp.close() + + def add_message(self, message): + self.messages.append(message) + + def __init__(self): + self.reset() + +if __name__ == "__main__": + tmp = address() + tmp.parse('2:5020/2120') + print tmp.string() diff --git a/contrib/u-srif/lib/unodestat.py b/contrib/u-srif/lib/unodestat.py new file mode 100644 index 0000000..d88b30a --- /dev/null +++ b/contrib/u-srif/lib/unodestat.py @@ -0,0 +1,102 @@ +import time +import gdbm +import ufido + +class nodestat: + """ [[month_id, month_size, month_num, month_time], + [week_id, seek_size, week_num, week_time], + [day_id, day_size, day_num, day_time], + [total_size, total_num, total_time]] + """ + def __init__(self, dbpath, address): + self.addr = address + self.key = address.string() + self.stat_session_size = 0 + self.stat_session_num = 0 + self.stat_session_time = 0 + self.stat_day_size = 0 + self.stat_day_num = 0 + self.stat_day_time = 0 + self.stat_week_size = 0 + self.stat_week_num = 0 + self.stat_week_time = 0 + self.stat_month_size = 0 + self.stat_month_num = 0 + self.stat_month_time = 0 + self.stat_total_size = 0 + self.stat_total_num = 0 + self.stat_total_time = 0 + self.dbpath = dbpath + tt = time.localtime() + self.month_id = time.strftime('%Y%m', tt) + self.week_id = time.strftime('%Y%W', tt) + self.day_id = time.strftime('%Y%j', tt) + self.notexist = 0 # Entry for this node doesn't exist yet? + + def upd_stat(self, num, size): + self.stat_session_size = self.stat_session_size + size + self.stat_session_num = self.stat_session_num + num + self.stat_month_size = self.stat_month_size + size + self.stat_month_num = self.stat_month_num + num + self.stat_week_size = self.stat_week_size + size + self.stat_week_num = self.stat_week_num + num + self.stat_day_size = self.stat_day_size + size + self.stat_day_num = self.stat_day_num + num + self.stat_total_size = self.stat_total_size + size + self.stat_total_num = self.stat_total_num + num + + def get_stat(self): + try: + db = gdbm.open(self.dbpath, 'r') + except gdbm.error: + return 0 + if not db.has_key(self.key): + self.notexist = 1 + db.close() + return 0 + entry = eval(db[self.key]) + # Check month statistic + if entry[0][0] == self.month_id: + self.stat_month_size = entry[0][1] + self.stat_month_num = entry[0][2] + self.stat_month_time = entry[0][3] + # Check week statistic + if entry[1][0] == self.week_id: + self.stat_week_size = entry[1][1] + self.stat_week_num = entry[1][2] + self.stat_week_time = entry[1][3] + # Check day statistic + if entry[2][0] == self.day_id: + self.stat_day_size = entry[2][1] + self.stat_day_num = entry[2][2] + self.stat_day_time = entry[2][3] + # Get total statistic + self.stat_total_size = entry[3][0] + self.stat_total_num = entry[3][1] + self.stat_total_time = entry[3][2] + db.close() + return 0 + + def put_stat(self): + db = gdbm.open(self.dbpath, 'cf') + # Don't handle exceptions + entry = [[self.month_id, self.stat_month_size, self.stat_month_num, self.stat_month_time], + [self.week_id, self.stat_week_size, self.stat_week_num, self.stat_week_time], + [self.day_id, self.stat_day_size, self.stat_day_num, self.stat_day_time], + [self.stat_total_size, self.stat_total_num, self.stat_total_time]] + db[self.key] = repr(entry) + db.close() + return 0 + +if __name__ == '__main__': + addr = ufido.address() + addr.parse('2:5020/2120') + ns = nodestat('./tmp.db', addr) + ns.upd_stat(2, 32768) + ns.put_stat() + addr2 = ufido.address() + addr2.parse('2:5020/2120') + ns2 = nodestat('./tmp.db', addr2) + ns2.get_stat() + print ns2.stat_total_num, ns2.stat_total_size + diff --git a/contrib/u-srif/lib/utmpl.py b/contrib/u-srif/lib/utmpl.py new file mode 100644 index 0000000..ea098b9 --- /dev/null +++ b/contrib/u-srif/lib/utmpl.py @@ -0,0 +1,97 @@ +import string + +class template: + def __init__(self): + self.local_address = '' + self.local_sysop = '' + self.local_location = '' + self.local_phone = '' + self.remote_address = '' + self.remote_sysop = '' + self.remote_location = '' + self.remote_phone = '' + self.remote_cid = '' + self.limit_size_day = -1 + self.limit_size_week = -1 + self.limit_size_month = -1 + self.sent_size_day = -1 + self.sent_size_week = -1 + self.sent_size_month = -1 + self.sent_size = -1 + self.conn_speed = -1 + self.text = None + + def set(self, srif=None, conf=None, nodestat=None): + if srif: + self.remote_address = srif.aka.string() + self.remote_sysop = srif.sysop + self.remote_location = srif.site + self.remote_cid = srif.callerid + self.conn_speed = srif.baud + if conf: + self.local_address = conf.local_address.string() + self.limit_size_day = conf.limit_size_day + self.limit_size_week = conf.limit_size_week + self.limit_size_month = conf.limit_size_month + if nodestat: + self.sent_session_size = nodestat.stat_session_size + self.sent_session_num = nodestat.stat_session_num + self.sent_day_size = nodestat.stat_day_size + self.sent_day_num = nodestat.stat_day_num + self.sent_week_size = nodestat.stat_week_size + self.sent_week_num = nodestat.stat_week_num + self.sent_month_size = nodestat.stat_month_size + self.sent_month_num = nodestat.stat_month_num + self.sent_total_size = nodestat.stat_total_size + self.sent_total_num = nodestat.stat_total_num + + def __cmd__(self, str): + try: + [fmt, arg] = string.split(str, ',', 1) + return eval('"' + fmt + '" % self.' + arg) + except ValueError: + return '@ValueError@' + except AttributeError: + return '@AttributeError@' + + def process(self, text=None): + if text == None: + text = self.text + if text == None: + return None + pos = 0 + while 1: + pos = string.find(text, '@', pos) + if pos < 0: + break + end_pos = string.find(text, '@', pos+1) + if end_pos < 0: + break + if end_pos - pos > 1: + # Process escaped command + replace = self.__cmd__(text[pos+1:end_pos]) + if replace: + text = text[:pos]+replace+text[end_pos+1:] + # Fix the current position + pos = end_pos + len(replace)-(end_pos-pos+1) + else: + # Leave text untouched + pos = end_pos + 1 + else: + # Replace '@@' by the single '@' + text = text[:pos+1]+text[pos+2:] + pos = end_pos + return text + + def readfile(self, path): + try: + fp = open(path, 'r') + self.text = fp.read() + fp.close() + except IOError: + pass + +if __name__ == "__main__": + test = template() + print test.process("'@@'\n'@@'\n'@%d,conn_speed@'\n'@@@'") + diff --git a/contrib/u-srif/lib/uutil.py b/contrib/u-srif/lib/uutil.py new file mode 100644 index 0000000..f412c70 --- /dev/null +++ b/contrib/u-srif/lib/uutil.py @@ -0,0 +1,54 @@ + +import string + +# Header for the files information +file_info_header = 'File Size Description\n'\ + + '-' * 78 + +class ULog: + def __init__(self, path): + self.path = path + self.fp = open(path, 'a') + + def puts(self, string): + fp.puts(strftime('%b %d %H:%M:%S ', gmtime())+string) + + def close(self): + fp.close() + +def format_desc(desc, offset, width=78): + """ Format file's description + """ + yield = '' + desc = string.expandtabs(desc, 1) + for line in string.split(desc, '\n'): + line = string.rstrip(line) + if line == '': + continue + pos = 0 + endpos = width + while line[pos:endpos]: + if yield: + yield = yield + '\n' + yield = yield + offset * ' ' + yield = yield + line[pos:endpos] + pos = endpos + endpos = endpos + width + return yield + +def format_file_info(name, size, desc, line_length=78): + """ Format file information to meet human requirements + """ + if size < 0: + yield = '%-20s ' % name + 11 * ' ' + else: + yield = '%-20s %-11d' % (name, size) + if desc: + offset = len(yield) + 1 + width = line_length - offset + desc = format_desc(desc, offset, width) + yield = yield + ' ' + string.lstrip(desc) + else: + yield = yield + ' Description not available' + return yield + diff --git a/contrib/u-srif/u-srif-index.py b/contrib/u-srif/u-srif-index.py new file mode 100644 index 0000000..14de806 --- /dev/null +++ b/contrib/u-srif/u-srif-index.py @@ -0,0 +1,50 @@ +#!/usr/bin/python + +import sys +import posix +import os +import libconf +import libfbase + +USRIF_CONFIG = '/usr/local/etc/u-srif/u-srif.conf' + +############################## +# The main program starts here + +# Read configuration +Conf = libconf.config(USRIF_CONFIG) + +# Open files index for writing +FBase = libfbase.filebase(Conf.spool_dir) +FBase.open('cwf') + +file = libfbase.file() + +# Process aliases from 'alias-list-file' +for alias in Conf.read_alias_list(): + print 'Processing alias "%s": %s' % (alias.name, alias.filename) + file_desc = libfbase.get_file_desc(alias.filename) + file.set(alias.filename, name = alias.name, desc = file_desc) + file.stat() + FBase.put(file) + +# Process dirs from 'dir-list-file' +for dir in Conf.read_dir_list(): + area_desc = libfbase.get_area_desc(dir) + print 'Processing: %s (%s)' % (dir, area_desc) + files_list = posix.listdir(dir) + for file_name in files_list: + full_name = os.path.join(dir, file_name) + if os.path.isfile(full_name): + file_desc = libfbase.get_file_desc(full_name) + file.set(full_name, area = area_desc, desc = file_desc) + file.stat() + FBase.put(file) + +# Purge files index +#print 'Purging removed files from files index' +#FBase.clean() + +FBase.close() +sys.exit(0) + diff --git a/contrib/u-srif/u-srif-lookup.py b/contrib/u-srif/u-srif-lookup.py new file mode 100644 index 0000000..867edc3 --- /dev/null +++ b/contrib/u-srif/u-srif-lookup.py @@ -0,0 +1,35 @@ +#!/usr/local/bin/python + +import sys + +# Our own libraries +sys.path.append('./lib') +import uconfig +import udbase +from uutil import * + +USRIF_CONFIG = '/usr/local/etc/u-srif/u-srif.conf' + +############################## +# The main program starts here +if len(sys.argv) < 2: + print 'usage:', sys.argv[0], '<[file] [file] ..>' + sys.exit(1) + +# Read configuration +Conf = uconfig.Config(USRIF_CONFIG) + +# Lookup files in the database +FBase = udbase.filebase(Conf.spool_dir) +FBase.open('r') +yield = FBase.get_all(sys.argv[1:]) +FBase.close() + +# Pretty printing +print file_info_header +for file in yield: + file.stat() + print format_file_info(file.name, file.size, file.desc) + +sys.exit(0) + diff --git a/contrib/u-srif/u-srif.py b/contrib/u-srif/u-srif.py new file mode 100644 index 0000000..b136c95 --- /dev/null +++ b/contrib/u-srif/u-srif.py @@ -0,0 +1,182 @@ +#!/usr/local/bin/python + +import string +import sys +import os + +# Our own libraries +sys.path.append('./lib') +import uconfig +import udbase +import ufido +import utmpl +import unodestat +from uutil import * + +USRIF_CONFIG = '/usr/local/etc/u-srif/u-srif.conf' + +class freq_report(ufido.message): + def write_packet(self, pktname): + self.packet.addr_orig = self.addr_orig + self.packet.addr_dest = self.addr_dest + self.packet.write(pktname) + + def add_file(self, name, size, desc): + text = format_file_info(name, size, desc) + self.append_text(text) + + def __init__(self): + ufido.message.__init__(self) + self.packet = ufido.packet() + self.packet.add_message(self) + +class srif_file: + def read_req_list(self): + yield = [] + fp = open(self.requestlist, 'r') + line = fp.readline() + while line: + line = string.strip(line) + yield.append(line) + line = fp.readline() + fp.close() + return yield + + def write_resp_list(self, list): + fp = open(self.responselist, 'w') + for file in list: + fp.write('+' + file + '\n') + fp.close() + + def read(self, name): + fp = open(name, 'r') + line = fp.readline() + while line: + line = string.strip(line) + args = string.split(line, None, 1) + if len(args) == 2: + if string.lower(args[0]) == 'sysop': + self.sysop = args[1] + if string.lower(args[0]) == 'aka': + self.aka.parse(args[1]) + elif string.lower(args[0]) == 'baud': + self.baud = args[1] + elif string.lower(args[0]) == 'requestlist': + self.requestlist = args[1] + elif string.lower(args[0]) == 'responselist': + self.responselist = args[1] + elif string.lower(args[0]) == 'remotestatus': + self.remotestatus = args[1] + elif string.lower(args[0]) == 'systemstatus': + self.systemstatus = args[1] + elif string.lower(args[0]) == 'site': + self.site = args[1] + elif string.lower(args[0]) == 'callerid': + self.callerid = args[1] + elif string.lower(args[0]) == 'password': + self.password = args[1] + else: + print "skipping keyword", args[0], "in SRIF" + line = fp.readline() + fp.close() + + def __init__(self, name): + self.sysop = '' + self.aka = ufido.address() + self.baud = 0 + self.requestlist = '' + self.responselist = '' + self.remotestatus = '' + self.systemstatus = '' + self.site = '' + self.callerid = '' + self.password = '' + self.read(name) + + def remote_addr(self): + return self.aka + + def isprotected(self): + if string.lower(self.remotestatus) == 'protected': + return 1 + return 0 + + def islisted(self): + if string.lower(self.systemstatus) == 'listed': + return 1 + return 0 + +def append_new_file(fileslist, file): + TotalFiles = TotalFiles + 1 + TotalSize = TotalSize + file.size + fileslist.append(file.fullname) + +############################## +# The main program starts here + +# Global variables +yield_list = [] + +if len(sys.argv) <> 2: + print 'usage: u-srif ' + sys.exit(1) + +# Read configuration +conf = uconfig.Config(USRIF_CONFIG) +# Read SRIF files +srif = srif_file(sys.argv[1]) +# Read node's statistic +nodestat = unodestat.nodestat(conf.stat_dbase, srif.aka) +nodestat.get_stat() + +# Lookup requested files in the our database +FBase = udbase.filebase(conf.spool_dir) +FBase.open('r') +yield = FBase.get_all(srif.read_req_list()) +FBase.close() + +# Prepare found files for sending +for file in yield: + if not file.fake: + file.stat() + nodestat.upd_stat(1, file.size) + yield_list.append(file.fullname) + +# Store node's statistic +nodestat.put_stat() + +# Send FREQ report? +if conf.send_report: + # Prepare templates object + tmpl = utmpl.template() + tmpl.set(srif=srif, conf=conf, nodestat=nodestat) + # Setup report object + report = freq_report() + report.newmsg(conf.local_address, conf.report_from, \ + srif.aka, srif.sysop, conf.report_subj) + report.append_line('') + # Append header + tmpl.readfile(conf.report_header) + text = tmpl.process() + if text: + report.append_text(text) + # Append per files statistic + for file in yield: + report.add_file(file.name, file.size, file.desc) + # Append footer + tmpl.readfile(conf.report_footer) + text = tmpl.process() + if text: + report.append_text(text) + # Add empty line to the report + report.append_line('') + # Create netmail packet with the FREQ report + pktname = '/var/tmp/12345678.pkt' # XXX + report.write_packet(pktname) + # Add packet file to the response files list + yield_list.append(pktname) + +# Dump reponse list +srif.write_resp_list(yield_list) +sys.exit(0) + diff --git a/debian/Makefile b/debian/Makefile new file mode 100644 index 0000000..1420701 --- /dev/null +++ b/debian/Makefile @@ -0,0 +1,242 @@ +# Makefile.in generated by automake 1.7.9 from Makefile.am. +# ../debian/Makefile. Generated from Makefile.in by configure. + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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. + +@SET_MAKE@ + +srcdir = . +top_srcdir = ../.. + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = /usr/bin/install -c +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = i686-pc-linux-gnu +host_triplet = i686-pc-linux-gnu +target_triplet = i686-pc-linux-gnu +CC = gcc +CFLAGS = -g -O2 +CPP = gcc -E +CPPFLAGS = +DEFS = -DHAVE_CONFIG_H +ECHO_C = +ECHO_N = -n +ECHO_T = +EGREP = grep -E +EXEEXT = +GROUP = news +INSTALL_DATA = ${INSTALL} -m 644 +INSTALL_PROGRAM = ${INSTALL} +INSTALL_SCRIPT = ${INSTALL} +LDFLAGS = +LIBOBJS = +LIBS = +LTLIBOBJS = +OBJEXT = o +OWNER = uucp +PACKAGE_BUGREPORT = ugenk@tut.by +PACKAGE_NAME = bforce +PACKAGE_STRING = bforce 0.22.8.ugenk2 +PACKAGE_TARNAME = bforce +PACKAGE_VERSION = 0.22.8.ugenk2 +PATH_SEPARATOR = : +SHELL = /bin/sh +YACC = bison -y +ac_ct_CC = gcc +bindir = ${exec_prefix}/bin +build = i686-pc-linux-gnu +build_alias = +build_cpu = i686 +build_os = linux-gnu +build_vendor = pc +datadir = ${prefix}/share +exec_prefix = ${prefix} +host = i686-pc-linux-gnu +host_alias = +host_cpu = i686 +host_os = linux-gnu +host_vendor = pc +includedir = ${prefix}/include +infodir = ${prefix}/info +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/libexec +localstatedir = ${prefix}/var +mandir = ${prefix}/man +oldincludedir = /usr/include +prefix = /usr/local +program_transform_name = s,x,x, +sbindir = ${exec_prefix}/sbin +sharedstatedir = ${prefix}/com +sysconfdir = ${prefix}/etc +target = i686-pc-linux-gnu +target_alias = +target_cpu = i686 +target_os = linux-gnu +target_vendor = pc + +# $Id$ +EXTRA_DIST = copyright changelog rules conffiles \ + control dirs init.d + +subdir = ../debian +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = +DIST_COMMON = $(srcdir)/Makefile.in Makefile.am +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu ../debian/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +uninstall-info-am: +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile + +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-info-am + +# 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/debian/Makefile.am b/debian/Makefile.am new file mode 100644 index 0000000..708dd19 --- /dev/null +++ b/debian/Makefile.am @@ -0,0 +1,3 @@ +# $Id$ +EXTRA_DIST = copyright changelog rules conffiles \ + control dirs init.d diff --git a/debian/Makefile.in b/debian/Makefile.in new file mode 100644 index 0000000..ff15767 --- /dev/null +++ b/debian/Makefile.in @@ -0,0 +1,242 @@ +# Makefile.in generated by automake 1.7.9 from Makefile.am. +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# 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. + +@SET_MAKE@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GROUP = @GROUP@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +OBJEXT = @OBJEXT@ +OWNER = @OWNER@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SHELL = @SHELL@ +YACC = @YACC@ +ac_ct_CC = @ac_ct_CC@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ + +# $Id$ +EXTRA_DIST = copyright changelog rules conffiles \ + control dirs init.d + +subdir = ../debian +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = +DIST_COMMON = $(srcdir)/Makefile.in Makefile.am +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu ../debian/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +uninstall-info-am: +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile + +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-info-am + +# 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/debian/README.Debian b/debian/README.Debian new file mode 100644 index 0000000..2ed9193 --- /dev/null +++ b/debian/README.Debian @@ -0,0 +1,6 @@ +bforce for Debian +----------------- + +See CHANGES.ugenk + + -- Evgeniy Kozhuhovskiy , Sun, 4 Oct 2004 11:14:15 +0200 diff --git a/debian/bfindex.1 b/debian/bfindex.1 new file mode 100644 index 0000000..d22ff14 --- /dev/null +++ b/debian/bfindex.1 @@ -0,0 +1,25 @@ +.TH BFINDEX "1" "April 2003" +.SH NAME +bfindex \- nodelist compiler for bforce +.SH SYNOPSYS +\fBbfindex [-fh]\fR + +.SH DESCRIPTION +\fBbfindex\fP is a nodelist compiler for BinkleyForce FTN mailer. +.SH OPTIONS +\fB\-f\fR +force nodelist compiling +.P +\fB-h\fR +show help message +.SH SEE ALSO +bforce(1),bfstat(1),nlookup(1) +.SH AUTHOR +Bforce was written by Alexander Belkin , 2:5020/2120 +.P +This manual page was written by Zhenja Kaluta + +This is free documentation; 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. diff --git a/debian/bforce.1 b/debian/bforce.1 new file mode 100644 index 0000000..7711408 --- /dev/null +++ b/debian/bforce.1 @@ -0,0 +1,68 @@ +.TH BFORCE "1" "April 2003" +.SH NAME +Bforce \- FTN mailer +.SH SYNOPSYS +\fBbforce [-fmh] [-I\fIinclude\fB] [-n\fIphone\fB]\ +[-l\fIline_number\fB] [-a\fIip_address\fB] \ +[-S\fIconnect\fB] [-p\fIdevice\fB] \fP<\fInode\fP> +.P +\fBbforce [-ih] [-I\fIinclude\fB] [-S\fIconnect\fB] \ +\fI +.P +\fBbforce [-dh] [-C\fIconfig\fB] [-I\fIinclude\fB] + +.SH DESCRIPTION +\fBbforce\fP BinkleyForce is a simple ifcico like FTN mailer. It can +works via TCP/IP as well as on modem links. +.SH OPTIONS +\fB\-d\fR +run as daemon +.P +\fB\-q\fR +terminate daemon +.P +\fB\-i\fR +run from inetd (for slave mode only) +.P +\fB\-f\fR +ignore system's work time +.P +\fB\-o\fR +starts outgoing session on stdin/stdout +.P +\fB-C \fIconfig\fR +main config file name. Default is ("/etc/bforce/bforce.conf") +.P +\fB-I \fIconfig\fR +additional config file name +.P +\fB-n \fIphone\fR +override phone number +.P +\fB-l \fIline_number\fR +call on this hidden line (default is 0) +.P +\fB-a \fIip_address\fR +override internet address +.P +\fB-S \fIconnect_str\fR +connect string (for slave mode only) +.P +\fB-p \fIport\fR +override modem port (must be defined in config) +.P +\fB-h\fR +show help message +.SH SEE ALSO +bfindex(1),bfstat(1),nlookup(1) +.SH AUTHOR +Bforce was written by Alexander Belkin , 2:5020/2120 +.P +This manual page was written by Zhenja Kaluta +.P +Revision 2 by Evgeniy Kozhuhovskiy + +This is free documentation; 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. diff --git a/debian/bforce.postinst.debhelper b/debian/bforce.postinst.debhelper new file mode 100644 index 0000000..1d46013 --- /dev/null +++ b/debian/bforce.postinst.debhelper @@ -0,0 +1,10 @@ +# Automatically added by dh_installinit +if [ -x "/etc/init.d/bforce" ]; then + update-rc.d bforce defaults >/dev/null + if [ -x /usr/sbin/invoke-rc.d ]; then + invoke-rc.d bforce start || exit 0 + else + /etc/init.d/bforce start || exit 0 + fi +fi +# End automatically added section diff --git a/debian/bforce.postrm.debhelper b/debian/bforce.postrm.debhelper new file mode 100644 index 0000000..8ec12eb --- /dev/null +++ b/debian/bforce.postrm.debhelper @@ -0,0 +1,5 @@ +# Automatically added by dh_installinit +if [ "$1" = "purge" ] ; then + update-rc.d bforce remove >/dev/null || exit 0 +fi +# End automatically added section diff --git a/debian/bforce.prerm.debhelper b/debian/bforce.prerm.debhelper new file mode 100644 index 0000000..854fcd3 --- /dev/null +++ b/debian/bforce.prerm.debhelper @@ -0,0 +1,9 @@ +# Automatically added by dh_installinit +if [ -x "/etc/init.d/bforce" ]; then + if [ -x /usr/sbin/invoke-rc.d ] ; then + invoke-rc.d bforce stop || exit 0 + else + /etc/init.d/bforce stop || exit 0 + fi +fi +# End automatically added section diff --git a/debian/bforce.substvars b/debian/bforce.substvars new file mode 100644 index 0000000..b7d6055 --- /dev/null +++ b/debian/bforce.substvars @@ -0,0 +1 @@ +shlibs:Depends=libc6 (>= 2.3.2.ds1-4) diff --git a/debian/bfstat.1 b/debian/bfstat.1 new file mode 100644 index 0000000..059651b --- /dev/null +++ b/debian/bfstat.1 @@ -0,0 +1,47 @@ +.TH BINDEX "1" "April 2003" +.SH NAME +bfstat \- binkley style outbound statistic +.SH SYNOPSYS +\fBbfstat [-afhprst] [-n \fInumber\fB]\fR +.SH DESCRIPTION +\fBbfstat\fP help you to see your outbound statistic in human readable +form. +.SH OPTIONS +\fB\-a\fR +sort by FTN address (default) +.P +\fB\-c\fR +print incoming/outgoing calls statistic +.P +\fB\-f\fR +disable queue sorting +.P +\fB\-n \fInumber\fR +don't print more than systems +.P +\fB\-p\fR +print sizes in human readable format +.P +\fB\-r\fR +reverse order while sorting +.P +\fB\-s\fR +sort by total files size +.P +\fB\-t\fR +disable total sizes printing +.P +\fB-h\fR +show help message +.SH SEE ALSO +bforce(1),bindex(1),nlookup(1) +.SH AUTHOR +Bforce was written by Alexander Belkin , 2:5020/2120 +.P +This manual page was written by Zhenja Kaluta +.P +Revision 2 by Evgeniy Kozhuhovskiy +This is free documentation; 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. diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..8e7c61c --- /dev/null +++ b/debian/changelog @@ -0,0 +1,27 @@ +bforce (0.22.8.ugenk3-1) unstable; urgency=low + + * New upstream release + * revision of manual pages + + -- Evgeniy Kozhuhovskiy Tue, 16 Nov 2004 08:42:04 +0200 + +bforce (0.22.8.ugenk2-2) unstable; urgency=low + + * fixed some bugs in configfiles + * sorry, bforce compiled without syslog support (maybe in the next version?) + + -- Evgeniy Kozhuhovskiy Tue, 2 Nov 2004 10:44:03 +0200 + +bforce (0.22.8.ugenk2-1) unstable; urgency=low + + * Initial Release. + * Really working rules ;) + + -- Evgeniy Kozhuhovskiy Sun, 31 Oct 2004 12:04:10 +0200 + +bforce (0.22.8.ugenk1-1) unstable; urgency=low + + * Initial Release. + + -- Evgeniy Kozhuhovskiy Sun, 4 Jul 2004 11:14:15 +0200 + diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/conffiles b/debian/conffiles new file mode 100644 index 0000000..2a12f5d --- /dev/null +++ b/debian/conffiles @@ -0,0 +1,6 @@ +/etc/bforce/bforce.conf +/etc/bforce/bforce.subst +/etc/bforce/bforce.passwd +/etc/bforce/freq.dirs +/etc/bforce/freq.aliases + diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..06c1945 --- /dev/null +++ b/debian/control @@ -0,0 +1,18 @@ +Source: bforce +Section: net +Priority: optional +Maintainer: Evgeniy Kozhuhovskiy +Build-Depends: debhelper (>> 3.0.0), dpatch (>= 1.11) +Standards-Version: 3.5.10 + +Package: bforce +Architecture: any +Depends: ${shlibs:Depends} +Description: Binkey Force FTN mailer + FTN mailer is a program that transmit files (netmail and echomail) + between your FTN node and other. + . + Bforce can be used to communicate over tcp/ip with binkp protocol or + with classic FTN way -- modem links. Bforce is easy to configure and + have good support of FTN standards. + diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..6dde283 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,14 @@ +This package was debianized by Evgeniy Kozhuhovskiy on +Sun, 4 Jul 2004 11:14:15 +0200. + +It was downloaded from http://ugenk.bas-net.by + +Upstream Author(s): Alexander Belkin, 2:5020/1398.11 + Konstantin Stepanenkov, 2:5030/1251 + Evgeniy Kozhuhovskiy, 2:450/256 + +Copyright: + +All programs are either under the GPL or LGPL. On Debian systems, +the complete text of the GPL and LGPL licenses can be found in the +/usr/share/common-licenses/GPL and /usr/share/common-licenses/LGPL files. \ No newline at end of file diff --git a/debian/default b/debian/default new file mode 100644 index 0000000..e157130 --- /dev/null +++ b/debian/default @@ -0,0 +1,2 @@ +# +RUN="no" diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..a966ac6 --- /dev/null +++ b/debian/dirs @@ -0,0 +1,13 @@ +usr/bin +etc/bforce +etc/default +etc/default/bforce +var/spool/fido/out +var/spool/fido/in +var/spool/fido/pin +var/spool/fido/ndl +var/spool/fido/fbox +var/spool/bforce +var/log/bforce +var/run/bforce + diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..e14b036 --- /dev/null +++ b/debian/docs @@ -0,0 +1,9 @@ +README +README.kst +README.ugenk +TODO +CHANGES +CHANGES.kst +CHANGES.ugenk +INSTALL +INSTALL.ru \ No newline at end of file diff --git a/debian/init.d b/debian/init.d new file mode 100644 index 0000000..05197be --- /dev/null +++ b/debian/init.d @@ -0,0 +1,61 @@ +#! /bin/sh +# +# skeleton example file to build /etc/init.d/ scripts. +# This file should be used to construct scripts for /etc/init.d. +# +# Written by Miquel van Smoorenburg . +# Modified for Debian +# by Ian Murdock . +# +# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl +# +# 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. + + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/bforce +NAME=bforce +DESC=bforce + +test -x $DAEMON || exit 0 + +# Include bforce defaults if available +if [ -f /etc/default/bforce ] ; then + . /etc/default/bforce +fi + +set -e + +case "$1" in + start) + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON -- $DAEMON_OPTS + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON + echo "$NAME." + ;; + restart|force-reload) + echo -n "Restarting $DESC: " + start-stop-daemon --stop --quiet --pidfile \ + /var/run/$NAME.pid --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --pidfile \ + /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS + echo "$NAME." + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/debian/nlookup.1 b/debian/nlookup.1 new file mode 100644 index 0000000..6e9d0a8 --- /dev/null +++ b/debian/nlookup.1 @@ -0,0 +1,30 @@ +.TH NLOOKUP "1" "April 2003" +.SH NAME +Bnlookup \- Nodelist search tool for bforce +.SH SYNOPSYS +\fBnlookup [-rh]\fR + +.SH DESCRIPTION +\fBnlookup\fP is a nodelist search tool for BinkleyForce FTN mailer. +.SH OPTIONS +\fB\-r\fR +show nodelist string +.P +\fB\-m\fR +show sysops e-mail (see FSP-1004.001 - p2) +.P +\fB-h\fR +show help message +.SH SEE ALSO +bforce(1),bfstat(1),nlookup(1) +.SH AUTHOR +Bforce was written by Alexander Belkin , 2:5020/2120 +.P +This manual page was written by Zhenja Kaluta +.P +Revision 2 by Evgeniy Kozhuhovskiy + +This is free documentation; 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. diff --git a/debian/outman.1 b/debian/outman.1 new file mode 100644 index 0000000..fbc657b --- /dev/null +++ b/debian/outman.1 @@ -0,0 +1,36 @@ +.TH OUTMAN "1" "November 2004" +.SH NAME +outman \- creates polls, file requests and attach files in aso and bso +.SH SYNOPSIS +.B outman +\fI<\fR[\fIpoll|freq|send\fR]\fI> \fR[\fIoptions\fR] \fI
\fR[\fIfiles\fR] +.SH DESCRIPTION +.SS "options:" +.TP +\fB\-hold\fR +set hold flavor +.TP +\fB\-normal\fR +set normal flavor (default) +.TP +\fB\-crash\fR +set crash flavor +.TP +\fB\-kill\fR +kill files after send +.HP +\fB\-truncate\fR truncate files after send +.PP +Mail bug reports to +.SH "SEE ALSO" +bfindex(1), bfstat(1), nlookup(1), bforce(1) +.SH AUTHOR +Bforce was written by Alexander Belkin , 2:5020/2120 +.P +This manual page was written by Evgeniy Kozhuhovskiy + +This is free documentation; 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. + diff --git a/debian/postinst b/debian/postinst new file mode 100644 index 0000000..c8464be --- /dev/null +++ b/debian/postinst @@ -0,0 +1,57 @@ +#! /bin/sh +# postinst script for bforce +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package +# +# quoting from the policy: +# Any necessary prompting should almost always be confined to the +# post-installation script, and should be protected with a conditional +# so that unnecessary prompting doesn't happen if a package's +# installation fails and the `postinst' is called with `abort-upgrade', +# `abort-remove' or `abort-deconfigure'. + +case "$1" in + configure) + + if ! grep -s news /etc/group >/dev/null 2>&1; then + addgroup --system news + fi + + if ! id uucp >/dev/null 2>&1; then + adduser --system --disabled-password uucp + chsh -s /bin/sh uucp + adduser uucp dialout + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff --git a/debian/postrm b/debian/postrm new file mode 100644 index 0000000..6fceeb0 --- /dev/null +++ b/debian/postrm @@ -0,0 +1,38 @@ +#! /bin/sh +# postrm script for bforce +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' overwrit>r> +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + + + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/debian/preinst b/debian/preinst new file mode 100644 index 0000000..fc6c30e --- /dev/null +++ b/debian/preinst @@ -0,0 +1,44 @@ +#! /bin/sh +# preinst script for bforce +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `install' +# * `install' +# * `upgrade' +# * `abort-upgrade' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + install|upgrade) +# if [ "$1" = "upgrade" ] +# then +# start-stop-daemon --stop --quiet --oknodo \ +# --pidfile /var/run/bforce.pid \ +# --exec /usr/sbin/bforce 2>/dev/null || true +# fi + ;; + + abort-upgrade) + ;; + + *) + echo "preinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff --git a/debian/prerm b/debian/prerm new file mode 100644 index 0000000..2fcf1fb --- /dev/null +++ b/debian/prerm @@ -0,0 +1,39 @@ +#! /bin/sh +# prerm script for bforce +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + remove|upgrade|deconfigure) +# install-info --quiet --remove /usr/info/bforce.info.gz + ;; + failed-upgrade) + ;; + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..aca946e --- /dev/null +++ b/debian/rules @@ -0,0 +1,111 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatibility version to use. +export DH_COMPAT=3 + + +PACKAGE = bforce + + + +ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) + CFLAGS += -g +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +configure: configure-stamp +configure-stamp: + dh_testdir +# Add here commands to configure the package. +# cat $(CURDIR)/source/Makefile.in | sed 's/\(^INSTALL_.*\)-o \$${OWNER} -g \$${GROUP}/\1/' > \ +# $(CURDIR)/source/Makefile.in.new +# mv $(CURDIR)/source/Makefile.in.new $(CURDIR)/source/Makefile.in + cd source; ./configure --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --sysconfdir=/etc/bforce -with-user=uucp --with-group=news + touch configure-stamp + + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + +# Add here commands to compile the package. + $(MAKE) -C source 2>/dev/null +# /usr/bin/docbook-to-man debian/bforce.sgml > bforce.1 + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + +# Add here commands to clean up after the build process. + -$(MAKE) -C source clean + dh_clean + rm -f source/config.cache source/include/config.h source/config.log\ + source/config.status source/Makefile + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + +# Add here commands to install the package into debian/bforce. +# $(MAKE) -C source install DESTDIR=$(CURDIR)/debian/bforce/ +# install $(CURDIR)/debian/default $(CURDIR)/debian/bforce/etc/default/bforce/ + /usr/bin/install -c -o uucp -g news source/bin/bforce $(CURDIR)/debian/bforce/usr/bin/bforce + /usr/bin/install -c -o uucp -g news source/bin/bfindex $(CURDIR)/debian/bforce/usr/bin/bfindex + /usr/bin/install -c -o uucp -g news source/bin/bfstat $(CURDIR)/debian/bforce/usr/bin/bfstat + /usr/bin/install -c -o uucp -g news source/bin/nlookup $(CURDIR)/debian/bforce/usr/bin/nlookup + /usr/bin/install -c -o uucp -g news contrib/outman $(CURDIR)/debian/bforce/usr/bin/outman + /usr/bin/install -c -m 644 -o uucp -g news examples/bforce.conf $(CURDIR)/debian/bforce/etc/bforce/bforce.conf + /usr/bin/install -c -m 644 -o uucp -g news examples/bforce.subst $(CURDIR)/debian/bforce/etc/bforce/bforce.subst + /usr/bin/install -c -m 644 -o uucp -g news examples/bforce.passwd $(CURDIR)/debian/bforce/etc/bforce/bforce.passwd + /usr/bin/install -c -m 644 -o uucp -g news examples/freq.aliases $(CURDIR)/debian/bforce/etc/bforce/freq.aliases + /usr/bin/install -c -m 644 -o uucp -g news examples/freq.dirs $(CURDIR)/debian/bforce/etc/bforce/freq.dirs + + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot +# dh_installdebconf + dh_installdocs -X.cvsignore + dh_installexamples examples/* +# dh_installlogrotate + dh_installinit +# dh_installcron + dh_installman $(CURDIR)/debian/bfindex.1 $(CURDIR)/debian/bforce.1 \ + $(CURDIR)/debian/bfstat.1 $(CURDIR)/debian/nlookup.1 +# dh_installinfo + dh_installchangelogs CHANGES + dh_link + dh_strip + dh_compress + dh_fixperms + chown -R uucp:news $(CURDIR)/debian/bforce/etc/bforce + chown -R uucp:news $(CURDIR)/debian/bforce/var/spool/fido $(CURDIR)/debian/bforce/var/spool/bforce + chown -R uucp:news $(CURDIR)/debian/bforce/var/log/bforce $(CURDIR)/debian/bforce/var/run/bforce +# dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/debian/rules-1 b/debian/rules-1 new file mode 100755 index 0000000..e8cc551 --- /dev/null +++ b/debian/rules-1 @@ -0,0 +1,96 @@ +#!/usr/bin/make -f + +# Uncomment this to turn on verbose mode. +export DH_VERBOSE=1 + +# This is the debhelper compatibility version to use. +export DH_COMPAT=3 + +PACKAGE = bforce + +ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) + CFLAGS += -g +endif +ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) + INSTALL_PROGRAM += -s +endif + +configure: #configure-stamp + +#configure-stamp: + dh_testdir + # Add here commands to configure the package. +# cat $(CURDIR)/source/Makefile.in | sed 's/\(^INSTALL_.*\)-o \$${OWNER} -g \$${GROUP}/\1/' > \ +# $(CURDIR)/source/Makefile.in.new +# mv $(CURDIR)/source/Makefile.in.new $(CURDIR)/source/Makefile.in + cd source; ./configure --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --sysconfdir=/etc/bforce --with-owner=uucp --with-group=news + touch configure-stamp + + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + + # Add here commands to compile the package. + $(MAKE) -C source +# /usr/bin/docbook-to-man debian/bforce.sgml > bforce.1 + + touch build-stamp + +#clean: unpatch +# dh_testdir +# dh_testroot +# rm -f build-stamp configure-stamp +# +# # Add here commands to clean up after the build process. +# -$(MAKE) -C source clean +# dh_clean +# rm -f source/config.cache source/include/config.h source/config.log\ +# source/config.status source/Makefile + +install: build + dh_testdir +# dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/bforce. + $(MAKE) -C source install DESTDIR=$(CURDIR)/debian/bforce +# install $(CURDIR)/debian/default $(CURDIR)/debian/bforce/etc/default/bforce + + +# Build architecture-independent files here. +binary-indep: configure build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: configure build install + dh_testdir + dh_testroot +# dh_installdebconf + dh_installdocs -X.cvsignore + dh_installexamples examples/* +# dh_installlogrotate + dh_installinit +# dh_installcron + dh_installman $(CURDIR)/debian/bfindex.1 $(CURDIR)/debian/bforce.1 \ + $(CURDIR)/debian/bfstat.1 $(CURDIR)/debian/nlookup.1 +# dh_installinfo + dh_installchangelogs CHANGES CHANGES.kst CHANGES.ugenk + dh_link + dh_strip + dh_compress + dh_fixperms + chown -R uucp:news $(CURDIR)/debian/bforce/etc/bforce + chown -R uucp:news $(CURDIR)/debian/bforce/var/spool/fido $(CURDIR)/debian/bforce/var/spool/bforce + chown -R uucp:news $(CURDIR)/debian/bforce/var/log/bforce $(CURDIR)/debian/bforce/var/run/bforce +# dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/examples/bforce.conf b/examples/bforce.conf new file mode 100644 index 0000000..3c104bf --- /dev/null +++ b/examples/bforce.conf @@ -0,0 +1,567 @@ +## +## This is an example binkleyforce configuration file +## +## Configuration line format: +## [()] +## +## For all addresses masks ``2:5020/*'' is equal to the ``2:5020/*.0'' +## +## Expression elements: +##
+## Time [,,..] +## Speed +## ConnSpeed +## Flag +## Exec +## Inbound, Outbound, Listed, Protected +## +## You can split long strings by adding '\' character to the end of previous +## line. Total length of string is unlimited. For example: +## +## Options NoZmodem \ +## NoZedZap +## +## Config reader directives: +## +## $INCLUDE Include this file +## $LOGFILE Log to this file +## $DEBUGFILE Write debug information to this file +## $DEBUGLEVEL Change debug level +## +## $IFEXP All data between ``$IFEXP'' and ``$ENDIF'' +## directives will be used with the specified +## .... expression, empty lines are unallowed +## $ENDIF +## +## Examples: +## +## $DEBUGLEVEL Outbound hShake +## +## $IFEXP ((2:*/*.* | !protected) & Time 23:00-01:00) +## options NoFreqs +## min_speed_in 14400 +## session_limit_in 600 +## $ENDIF +## + +$INCLUDE /usr/local/fido/etc/bforce.subst +$INCLUDE /usr/local/fido/etc/bforce.passwd + +address 2:450/256.0@fidonet +address 2:450/247.128@fidonet +address 20:26/100.0@easynet + +# +# Hide addresses from remote, where
must be one of your AKAs +# +# hide_our_aka
+# + +# +# Allowed options: +# [No]Zmodem, [No]ZedZap, [No]DirZap, [No]Janus, [No]Hydra +# [No]Chat, [No]FTS1, [No]YooHoo, [No]EMSI, [No]EMSI-II +# [No]Freqs, [No]MailOnly, [No]HoldXT, [No]HoldReq, [No]HoldHold +# [No]HoldAll, [No]PickUp, [No]RH1 +# +# Now it is highly recommended to set at least "NoDirZap NoJanus" +# +options NoDirZap NoJanus NoChat + +# +# Domain outbounds +# Domain +# +#domain lasernet /var/spool/ftn/lasernet/ 161 +#domain medianet /var/spool/ftn/medianet/ 776 +#domain schoolnet /var/spool/ftn/schoolnet/ 461 + +# +# Log/debug file names (if not defined, used builtins) +# +#log_file_daemon /var/log/bforce/bf-daemon +#log_file /var/log/bforce/bf-log +#debug_file /var/log/bforce/bf-debug + +# +# Existing of this file forbid any outgoing modem calls. Existing of +# file with name .ttyS1 forbid outgoing calls only via +# modem on device /dev/ttyS1, and so on. +# +nodial_flag /etc/nodial + +# +# Debugging information completness level. Debugging is disabled by +# default. Allowed debug levels: config, nodelist, outbound, info, hshake, +# ttyio, modem, prot, freq, daemon, full +# +# It seems to be broken now, use "$DEBUGLEVEL" instead +# +#debug_level info hshake prot +# + +# +# Inbound directories +# +inbound_directory (Protected) /var/spool/fido/bt/pin +inbound_directory /var/spool/fido/bt/in + +# +# Path to your 4D outbound (use zone as extension) +# +#outbound_directory /var/spool/fido/bt/out + +# +# Path to your AmigaDos style 4D outbound. +# (You can use all outbound styles at the same time) +# +amiga_outbound_directory /var/spool/fido/bt/out + +# +# Directory with your nodelists (for nodelist without full path) +# +nodelist_directory /var/spool/fido/ndl + +# +# Directory for status files +# +status_directory /var/spool/fido/bforce + +# +# Sessions history +# +history_file /var/log/bforce/history + +# +# Minimal connect speeds for incoming/outgoing sessions +# +#min_speed_in 1200 +#min_speed_out 1200 + +# +# Time limit for incoming/outgoing session [seconds] +# +#session_limit_in 1800 +#session_limit_out 1800 + +# +# Abort transfer if minimal CPS stays longer this time (in seconds) +# Default value is 60 seconds. +# +#min_cps_time 120 + +# +# Force usage of this value as minimal CPS (most priority) +# min_cps_recv +# min_cps_send +# +# For example: +# min_cps_recv (2:5020/1398) 2100 +# min_cps_recv (2:5020/1682) 3000 +# min_cps_recv (2:5020/1811) 1400 + +# +# Minimal CPS values for Zmodem ,ZedZap, DirZap protocols (Receive/Send) +# +# +# +zmodem_mincps_recv 300 15 +zmodem_mincps_recv 1200 90 +zmodem_mincps_recv 2400 120 +zmodem_mincps_recv 4800 240 +zmodem_mincps_recv 7200 360 +zmodem_mincps_recv 9600 480 +zmodem_mincps_recv 12000 600 +zmodem_mincps_recv 14400 720 +zmodem_mincps_recv 16800 840 +zmodem_mincps_recv 19200 960 +zmodem_mincps_recv 21600 1080 +zmodem_mincps_recv 23600 1180 +zmodem_mincps_recv 24000 1200 +zmodem_mincps_recv 26400 1320 +zmodem_mincps_recv 28800 1440 +zmodem_mincps_recv 31200 1600 +zmodem_mincps_recv 33600 1700 + +zmodem_mincps_send 300 15 +zmodem_mincps_send 1200 90 +zmodem_mincps_send 2400 120 +zmodem_mincps_send 4800 240 +zmodem_mincps_send 7200 360 +zmodem_mincps_send 9600 480 +zmodem_mincps_send 12000 600 +zmodem_mincps_send 14400 720 +zmodem_mincps_send 16800 840 +zmodem_mincps_send 19200 960 +zmodem_mincps_send 21600 1080 +zmodem_mincps_send 23600 1180 +zmodem_mincps_send 24000 1200 +zmodem_mincps_send 26400 1320 +zmodem_mincps_send 28800 1440 +zmodem_mincps_send 31200 1600 +zmodem_mincps_send 33600 1700 + +hydra_mincps_recv 300 15 +hydra_mincps_recv 1200 90 +hydra_mincps_recv 2400 120 +hydra_mincps_recv 4800 240 +hydra_mincps_recv 7200 360 +hydra_mincps_recv 9600 480 +hydra_mincps_recv 12000 600 +hydra_mincps_recv 14400 720 +hydra_mincps_recv 16800 840 +hydra_mincps_recv 19200 960 +hydra_mincps_recv 21600 1080 +hydra_mincps_recv 23600 1180 +hydra_mincps_recv 24000 1200 +hydra_mincps_recv 26400 1320 +hydra_mincps_recv 28800 1440 +hydra_mincps_recv 31200 1600 +hydra_mincps_recv 33600 1700 + +hydra_mincps_send 300 15 +hydra_mincps_send 1200 90 +hydra_mincps_send 2400 120 +hydra_mincps_send 4800 240 +hydra_mincps_send 7200 360 +hydra_mincps_send 9600 480 +hydra_mincps_send 12000 600 +hydra_mincps_send 14400 720 +hydra_mincps_send 16800 840 +hydra_mincps_send 19200 960 +hydra_mincps_send 21600 1080 +hydra_mincps_send 23600 1180 +hydra_mincps_send 24000 1200 +hydra_mincps_send 26400 1320 +hydra_mincps_send 28800 1440 +hydra_mincps_send 31200 1600 +hydra_mincps_send 33600 1700 + +# +# Automatically set this permissions on the received files +# +mode_default 100660 +mode_arcmail 100660 +mode_netmail 100660 +mode_request 100660 + +# +# In modem commands you can use: +# '|' cartidge return +# '^' high DTR +# 'v' low DTR +# '~' 1 second delay +# '`' 1/4 second delay + +# +# Yor modem devices names (will use first not locked one) +# ModemDev [<:lock_speed>] +# +modem_port /dev/ttyS0:57600 + +# +# Send this string to modem before calling +# +modem_reset_command AT| + +# +# Dial string +# +modem_dial_prefix ATDP + +# +# Dial string +# +modem_dial_suffix | + +# +# Hangup string +# +modem_hangup_command v~^~ATH0| + +# +# Command for getting modem statistic (after outgoing sessions) +# +# +#modem_stat_command AT%S| +# if your modem do not send statistic, use this: +modem_stat_command AT| + +# +# List of modem responses on modem dial command +# +# First field is substring of modem response string, first match used! +# +# Second field value Default return code +# connect -- +# busy 11 +# nocarrier 12 +# nodialtone 13 +# noanswer 14 +# error 15 +# +# You are free to use something like: ModemDialResp "LINE IN USE" Error 200 +# +# [Return code] +# +modem_dial_response "CONNECT" connect +modem_dial_response "BUSY" busy +modem_dial_response "NO CARRIER" nocarrier +modem_dial_response "NO DIAL" nodialTone +modem_dial_response "NO ANSWER" noanswer +modem_dial_response "VOICE" noanswer +modem_dial_response "ERROR" error + +# +# Your nodelists. Will try all nodelists with matching address mask. +# +nodelist nodelist.ndl *:*/*.0 +nodelist 450_256.pnt 2:450/256.* +nodelist easynet.ndl 20:26/*.0 +nodelist *:*/*.* + +# +# Nodelist phone numbers translation +# phone_translate [to_what_translate] + +phone_translate 375-17- +phone_translate 375- 8W + + +# +# Your system information (for EMSI only) +# +system_name XXX Station +location Minsk, Belarus +sysop_name Evgeniy Kozhuhovskiy +phone 375-17-2250238, voice: 375-29-5586164 +max_speed 57600 +flags XW,V34B,IDC,LMD +emsi_OH_time 22:00-07:30 +emsi_FR_time 22:30-05:30 + +# +# Our receiver buffer size [bytes] +# +recv_buffer_size 65536 + +# +# Wait for modem response this time at calling [seconds] +# +wait_carrier_out 120 + +# Command to run external SRIF processor +# +#freq_srif_command /usr/local/lib/u-srif/u-srif + +# +# Files with list of aliases and dirs for FREQs +# +freq_alias_list /usr/local/fido/etc/freq.aliases +freq_dir_list /usr/local/fido/etc/freq.dirs + +# +# Maximal number of files to send on FREQs +# +freq_limit_number 10 + +# +# Size limit for file requests [bytes] +# +freq_limit_size 6000000 + +# +# _SEND_ requested files not longer this time [seconds] +# +freq_limit_time 1200 + +# +# Ignore this masks in file requests +# +freq_ignore_masks \\* \\*.\\* \\*.zip \\*.rar \\*.tgz \\*.mp3 + +# +# Skip files with ZRPOS on zmodem protocol (else use ZSKIP) +# +#zmodem_skip_by_pos yes + +# +# Binkleyforce will send empty netmail packet on Zmodem/ZedZap/DirZap +# protocols if there is nothing to send (default - No) +# +zmodem_send_dummy_pkt no + +# +# Initial block size [bytes] for Zmodem/ZedZap/DirZap protocols +# +#zmodem_start_block_size 512 + +# +# Tx window size [bytes] for Zmodem/ZedZap/DirZap protocols +# +#zmodem_tx_window 32768 + +# +# Automaticaly skip files with such names at receiving +# +skip_files_recv *.pif *.swp + +# +# Delay files with such names at receiving/sending +# +#delay_files_recv !%arcmail !%netmail # We will refuse all except mail +#delay_files_send !%netmail # We will send only netmail +# # packets +# +# Our netmail-only uplink +#delay_files_recv (2:450/102) !%netmail +# +# Binkleyforce will delay all receiving files if free space space +# in the inbound directory is lower this value [Kbytes] +# +#min_free_space 20000 + +# +# Tables for recoding to another charset. Tables format is compartible +# with HPT, FTrack and possible with something else. +# +# File names recoding +#recode_file_out /usr/local/fido/etc/koi82alt.tbl +#recode_file_in /usr/local/fido/etc/alt2koi8.tbl +# Intro recoding (Buggy Sidoroff) +#recode_intro_in (2:450/236) /usr/local/fido/etc/alt2koi8.tbl + +# +# External programs support. Possible execution options: +# +# nowait - don't wait for the process termination +# logout - write stdout/stderr to the log +# setsid - run command in a new session +# useshell - run command by calling a shell (/bin/sh) +# +#run_after_handshake [logout]/bin/echo "Hello, world!" +#run_after_session [nowait,setsid]/usr/local/lib/ftp/run-in +# +# To see a nodelist node information in the log file, write: +# +#run_after_handshake [useshell,logout]/usr/local/lib/ftn/nlookup $REM_ADDR_FTN + +# +# Path to the directory with "long" fileboxes. Such fileboxes names +# has the format "..." (e.g. "2.5020.2120.0"). +# The files from such fileboxes are allways queued with a "hold" flavor +# +#filebox_directory /var/spool/fido/bt/fbox + +# +# Personal fileboxes +# filebox
[flavor] +# +#filebox /var/spool/ftn/fbox/adb 2:5020/2120.1 hold +#filebox /var/spool/ftn/fbox/pvc 2:5020/2091 normal + +# +# ?LO files content translation rules +# flo_translate +# +#flo_translate C:\\fido\\spool\\outbound /var/spool/ftn/out +#flo_translate \\ / + +####################### +# DAEMON configuration + +# +# Try counters short description: +# +# [] +# +# Allowed 'Keywords': +# 'Maxtries' +# Increase : every time when we call system +# Reset : successful session +# 'Maxtries_noansw' +# Increase : modem return "noanswer" +# Reset : connect +# 'Maxtries_noconn' +# Increase : cannot connect +# Reset : connect +# 'Maxtries_hshake' +# Increase : handshake failure +# Reset : successful handshake +# 'Maxtries_sessions' +# Increase : any failures after connect (including connect speed too low) +# Reset : successful session +# 'Maxtries_nodial' +# Increase : modem return "nodialtone" +# Reset : connect +# +# Allowed 'Actions': +# 'Undialable' - set undialable flag to the system, so we will never try +# to call it more +# 'Hold' - don't call system during next seconds +# 'HoldAll' - don't make outgoing calls to ANY system during next +# seconds +# + +maxtries 200 Undialable # Be carefull.. =) +maxtries_noansw 5 Hold 7200 # Call two hours later +maxtries_noconn 40 Hold 10800 # Don't call 3 hours +maxtries_hshake 10 Hold 86400 # 1 day delay +maxtries_sessions 10 Hold 3600 # Don't annoy uplinks +maxtries_nodial 1 Hold 1200 # Call 20 min later + +# +# Minimum delay between reusings of the same modem [seconds] +# +daemon_circle_modem 40 + +# +# Outbound queue rescan interval [seconds] +# +daemon_circle_rescan 60 + +# +# Minimum delay between two outgoing calls to the same system, +# depending on the mail/files flavor [seconds] +# +daemon_circle_normal 80 +daemon_circle_direct 40 +daemon_circle_crash 20 +daemon_circle_immed 10 + +# +# Maximum number of the simultaneously running TCP/IP clients. Zero value +# will forbid any outgoing calls via TCP/IP +# +daemon_maxclients_tcpip 3 + +# +# Maximum number of the simultaneously running modem clients. Zero value +# will forbid any outgoing calls via modems +# +daemon_maxclients_modem 1 + +# +# Daemon PID file name +# +daemon_pid_file /var/run/bforce.pid + +# +# Syslog facility (see man 3 openlog and /usr/include/sys/syslog.h for list of facilities) +# 64 == 8<3 == +# See SYSLOG for details +# +syslog_facility 64 + +# +# Where to listen (0.0.0.0 for all available) +# +bind_ip 127.0.0.1 + +# +# Holdall flag (if exists, no mail will sent) +# +nomail_flag /etc/nomail + + +# That's all! diff --git a/examples/bforce.passwd b/examples/bforce.passwd new file mode 100644 index 0000000..c5149e3 --- /dev/null +++ b/examples/bforce.passwd @@ -0,0 +1,9 @@ +# +# Format: password
+# + +password 2:5020/1398 passwd1 +password 2:5020/1682 passwd2 +password 2:5020/1811 passwd3 +password 776:308/8 passwd4 + diff --git a/examples/bforce.subst b/examples/bforce.subst new file mode 100644 index 0000000..14a3071 --- /dev/null +++ b/examples/bforce.subst @@ -0,0 +1,33 @@ +# +# Example of overriding node with hidden lines: +# Override 1:2/3 Phone 123-1313 Worktime 21:00-07:00 \ +# Hidden Phone 123-1314 Worktime 09:00-13:00 \ +# Hidden Phone 123-1315 Worktime 09:00-21:00 \ +# Hidden Phone 123-1316 Flags CM +# +# You may specify different time for different days of week: +# Override 1:2/3 Phone 123-1313 Worktime Wk20:00-07:30,We00:00-24:00 +# +# Allowed day prefixes: Sun, Mon, Tue, Wed, Thu, Fri, Sat, Any, Wk, We +# +# To use BinkP protocol, write: +# Override 1:2/3 Ipaddr f3.n2.z1.fidonet.net Flags CM,BINKP +# +# If you want never call to certain node, write: +# Override 1:2/3 Phone Unpublished +# +# Happy +override 776:308/1 Ipaddr 192.168.1.1 Flags CM,IFC +override 776:308/1.1 Ipaddr 192.168.1.2 Flags CM,BINKP + +# Estar +override 2:5020/758 Phone 961-2243 + +# Hard Core +override 2:5020/1398 Phone 700-0245 Worktime 00:00-07:00 + +# Stick's +override 2:5020/1682 Phone 308-5537 Worktime 23:30-07:00 + +override 2:5020/2120 Ipaddr 192.168.1.1 flags BINKP,CM + diff --git a/examples/freq.aliases b/examples/freq.aliases new file mode 100644 index 0000000..4fd5d79 --- /dev/null +++ b/examples/freq.aliases @@ -0,0 +1,6 @@ +# +# [!] +# +#files /home/ftp/pub/info/happy.zip +#filelist /home/ftp/pub/info/happy.lst +#test /home/ftp/pub/fileecho/PNT5020/pnt5020.zip diff --git a/examples/freq.dirs b/examples/freq.dirs new file mode 100644 index 0000000..ab9cebe --- /dev/null +++ b/examples/freq.dirs @@ -0,0 +1,10 @@ +# +# [!] +# + +#/home/ftp/secure/doc/xxx.zip !fdsn02vz +#/home/ftp/pub/fileecho/AFTNMISC/ +#/home/ftp/pub/fileecho/AVP/ +#/home/ftp/pub/fileecho/LARRY.FILES/ +#/home/ftp/pub/fileecho/MOBIL/ +#/home/ftp/pub/fileecho/NET5020/ \ No newline at end of file diff --git a/patch-stamp b/patch-stamp new file mode 100644 index 0000000..7f70809 --- /dev/null +++ b/patch-stamp @@ -0,0 +1,2 @@ +Patches applied in the Debian version of : + diff --git a/rpm/bforce.spec b/rpm/bforce.spec new file mode 100644 index 0000000..f07f0ff --- /dev/null +++ b/rpm/bforce.spec @@ -0,0 +1,70 @@ +Summary: Bforce, Fidonet mailer +Name: bforce +Version: 0.22.8 +Release: ugenk2 +Copyright: GPL +Group: Fidonet/mailer +Source0: bforce-%{version}.%{release}.tar.gz +BuildRoot: %{_tmppath}/%{name}-root + +%description +BFORCE is a FTN mailer. Supports PSTN and binkp sessions. + +%prep +%setup -q -n %{name}-%{version}.%{release} + +cd source +./configure --prefix=/usr --disable-log-passwd --sysconfdir=/etc/bforce --bindir=/usr/bin --with-owner=uucp --with-group=news + +%build +cd source +make + +%install +rm -rf $RPM_BUILD_ROOT + +mkdir -p $RPM_BUILD_ROOT/etc/bforce +mkdir -p $RPM_BUILD_ROOT/usr/bin +mkdir -p $RPM_BUILD_ROOT/usr/sbin +mkdir -p $RPM_BUILD_ROOT/var/log/bforce +mkdir -p $RPM_BUILD_ROOT/var/spool/fido/bt/pin +mkdir -p $RPM_BUILD_ROOT/var/spool/fido/bt/in +mkdir -p $RPM_BUILD_ROOT/var/spool/fido/ndl +mkdir -p $RPM_BUILD_ROOT/var/spool/fido/bforce + + +install -o uucp -g news source/bin/bforce $RPM_BUILD_ROOT/usr/bin/bforce +install -o uucp -g news source/bin/bfindex $RPM_BUILD_ROOT/usr/bin/bfindex +install -o uucp -g news source/bin/bfstat $RPM_BUILD_ROOT/usr/bin/bfstat +install -o uucp -g news source/bin/nlookup $RPM_BUILD_ROOT/usr/bin/nlookup +install -o uucp -g news examples/bforce.conf $RPM_BUILD_ROOT/etc/bforce/bforce.conf.sample +install -o uucp -g news examples/bforce.passwd $RPM_BUILD_ROOT/etc/bforce/bforce.passwd.sample +install -o uucp -g news examples/bforce.subst $RPM_BUILD_ROOT/etc/bforce/bforce.subst.sample +install -o uucp -g news examples/freq.aliases $RPM_BUILD_ROOT/etc/bforce/freq.aliases.sample +install -o uucp -g news examples/freq.dirs $RPM_BUILD_ROOT/etc/bforce/freq.dirs.sample +install -m755 -o uucp -g news contrib/outman $RPM_BUILD_ROOT/usr/bin/outman + + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%doc README README.kst CHANGES CHANGES.kst COPYING INSTALL.ru README.ugenk + +%attr(550,uucp,news) /usr/bin/bforce +%attr(550,uucp,news) /usr/bin/bfindex +%attr(550,uucp,news) /usr/bin/bfstat +%attr(550,uucp,news) /usr/bin/nlookup +%attr(550,uucp,news) /usr/bin/outman +%attr(644,root,root) /usr/share/doc/bforce-0.22.8/* +%dir %attr(770,uucp,news) /var/log/bforce +%dir %attr(770,uucp,news) /var/spool/fido/ndl +%attr(775,uucp,news) /var/spool/fido/bt +%config %attr(600,uucp,news) /etc/bforce/bforce.conf.sample +%config %attr(600,uucp,news) /etc/bforce/bforce.subst.sample +%config %attr(600,uucp,news) /etc/bforce/bforce.passwd.sample +%config %attr(600,uucp,news) /etc/bforce/freq.aliases.sample +%config %attr(600,uucp,news) /etc/bforce/freq.dirs.sample + + + diff --git a/rpm/buildrpm.sh b/rpm/buildrpm.sh new file mode 100755 index 0000000..331e4cf --- /dev/null +++ b/rpm/buildrpm.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +RPMROOT='/home/ugenk/rpm' + +if [ `whoami` != "root" ]; then + echo "$0: your must be root run this script." + exit 1 +fi + + +cd ../source + +make distclean + +cd - + +rm -f *.gz + +tar -cvf bforce-`cat ../source/.version`.tar ../../bforce-`cat ../source/.version`/source/ ../../bforce-`cat ../source/.version`/CHANGES* ../../bforce-`cat ../source/.version`/COPYING ../../bforce-`cat ../source/.version`/INSTALL* ../../bforce-`cat ../source/.version`/README* ../../bforce-`cat ../source/.version`/SYSLOG ../../bforce-`cat ../source/.version`/TODO ../../bforce-`cat ../source/.version`/contrib ../../bforce-`cat ../source/.version`/examples ../../bforce-`cat ../source/.version`/debian + +gzip bforce-`cat ../source/.version`.tar + +cp -f bforce-`cat ../source/.version`.tar.gz $RPMROOT/SOURCES/ + +rpm -ba bforce.spec + diff --git a/source/.version b/source/.version new file mode 100644 index 0000000..6260cde --- /dev/null +++ b/source/.version @@ -0,0 +1 @@ +0.22.8.ugenk4 diff --git a/source/Makefile b/source/Makefile new file mode 100644 index 0000000..260cded --- /dev/null +++ b/source/Makefile @@ -0,0 +1,185 @@ +# +# Copyright (c) 1999-2000, Alexander Belkin +# +# $Id$ +# + +CC = gcc +INCLUDES = -I./include +CFLAGS = -g -O2 +LIBS = +YACC = bison -y +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 +SRCDIR = . +SRCDIRCONF = $(SRCDIR)/../examples +CONTRIBDIR = $(SRCDIR)/../contrib + +OWNER = uucp +GROUP = news +CONFDIR = /usr/local/etc +BINDIR = /usr/local/bin +LOGDIR = /var/log/bforce +SPOOLDIR = /var/spool/bforce + +DAEMON_LOGFILE = $(LOGDIR)/bf-daemon +BFORCE_LOGFILE = $(LOGDIR)/bf-log +BFORCE_DEBFILE = $(LOGDIR)/bf-debug +BFORCE_CFGFILE = $(CONFDIR)/bforce.conf + +DEFINES = -DDAEMON_LOGFILE=\"$(DAEMON_LOGFILE)\" \ + -DBFORCE_LOGFILE=\"$(BFORCE_LOGFILE)\" \ + -DBFORCE_DEBFILE=\"$(BFORCE_DEBFILE)\" \ + -DBFORCE_CFGFILE=\"$(BFORCE_CFGFILE)\" \ + -DBF_OS=\"linux-gnu\" -DHAVE_CONFIG_H + +SUBDIRS = bforce bfutil + +BFINDEX_OBJS = bfutil/bfindex.o \ + bforce/conf_deinit.o bforce/conf_proc.o \ + bforce/conf_read.o bforce/conf_get.o \ + bforce/logger.o bforce/nodelist.o \ + bforce/u_file.o bforce/u_ftn.o \ + bforce/u_misc.o bforce/u_string.o \ + bforce/u_time.o + +NLOOKUP_OBJS = bfutil/nlookup.o \ + bforce/conf_deinit.o bforce/conf_proc.o \ + bforce/conf_read.o bforce/conf_get.o \ + bforce/logger.o bforce/nodelist.o \ + bforce/u_file.o bforce/u_ftn.o \ + bforce/u_misc.o bforce/u_string.o \ + bforce/u_time.o + +BFSTAT_OBJS = bfutil/bfstat.o \ + bforce/conf_deinit.o bforce/conf_proc.o \ + bforce/conf_read.o bforce/conf_get.o \ + bforce/outb_flo.o bforce/outb_fsqueue.o \ + bforce/sess_stat.o \ + bforce/outb_getname.o bforce/outb_sysqueue.o \ + bforce/outb_scan.o bforce/logger.o \ + bforce/u_file.o \ + bforce/u_ftn.o bforce/u_misc.o \ + bforce/u_string.o bforce/u_time.o \ + bforce/u_plock.o + +BFORCE_OBJS = bforce/bforce.o \ + bforce/daemon.o bforce/daemon_branch.o \ + bforce/daemon_call.o bforce/daemon_lines.o \ + bforce/conf_deinit.o \ + bforce/conf_proc.o bforce/conf_read.o \ + bforce/conf_get.o bforce/expression.o \ + bforce/freq_bark.o bforce/freq_proc.o \ + bforce/freq_srif.o bforce/freq_wazoo.o \ + bforce/io_modem.o bforce/io_tcpip.o \ + bforce/io_unix_lock.o bforce/io_unix_modem.o \ + bforce/io_unix_tio.o bforce/io_unix_tty.o \ + bforce/logger.o bforce/nodelist.o \ + bforce/os_unix.o bforce/outb_bsy.o \ + bforce/outb_flo.o bforce/outb_fsqueue.o \ + bforce/outb_getname.o bforce/outb_sysqueue.o \ + bforce/outb_scan.o bforce/prot_common.o \ + bforce/prot_binkp.o bforce/prot_binkp_api.o \ + bforce/prot_binkp_misc.o bforce/prot_hydra.o \ + bforce/prot_xmrecv.o bforce/prot_xmsend.o \ + bforce/prot_zmmisc.o bforce/prot_zmrecv.o \ + bforce/prot_zmsend.o \ + bforce/prot_yoohoo.o bforce/prot_yoohoo_api.o \ + bforce/prot_emsi.o bforce/prot_emsi_misc.o \ + bforce/prot_emsi_api.o \ + bforce/sess_common.o bforce/sess_stat.o \ + bforce/sess_call.o bforce/sess_answ.o \ + bforce/sess_init.o bforce/sess_main.o \ + bforce/u_crc.o bforce/u_ftn.o \ + bforce/u_md5.o \ + bforce/u_misc.o bforce/u_string.o \ + bforce/u_time.o bforce/u_file.o \ + bforce/u_pkt.o bforce/u_recode.o \ + bforce/u_plock.o + +.c.o: + @echo Compiling $*.c + @$(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ + +all: bin/bforce bin/bfindex bin/bfstat bin/nlookup + +expression.c: bforce/expression.y + $(YACC) bforce/expression.y + mv y.tab.c bforce/expression.c + +bin/bforce: $(BFLIB_OBJS) $(BFORCE_OBJS) + @echo "Linking $@" + @$(CC) $(BFLIB_OBJS) $(BFORCE_OBJS) $(LIBS) -o $@ + +bin/bfindex: $(BFLIB_OBJS) $(BFINDEX_OBJS) + @echo "Linking $@" + @$(CC) $(BFLIB_OBJS) $(BFINDEX_OBJS) $(LIBS) -o $@ + +bin/nlookup: $(BFLIB_OBJS) $(NLOOKUP_OBJS) + @echo "Linking $@" + @$(CC) $(BFLIB_OBJS) $(NLOOKUP_OBJS) $(LIBS) -o $@ + +bin/bfstat: $(BFLIB_OBJS) $(BFSTAT_OBJS) + @echo "Linking $@" + @$(CC) $(BFLIB_OBJS) $(BFSTAT_OBJS) $(LIBS) -o $@ + + +clean: + @for i in $(SUBDIRS); do (rm -f $$i/*.o || exit 1); done + rm -f ./bforce/expression.c + rm -f ./bin/bforce + rm -f ./bin/bfindex + rm -f ./bin/bfstat + rm -f ./bin/nlookup + rm -f ./bin/core +clean-am: + rm -f ./Makefile + rm -f ./include/config.h + rm -f ./config.log + rm -f ./config.status +clean-ac: + rm -f ./configure + +distclean: clean clean-am + +distclean-m: distclean clean-ac + + +ifnames: + @for i in $(SUBDIRS); do (ifnames $$i/*.c || exit 1); done + +bforce/expression.y.o: bforce/expression.y.c bforce/expression.l.c + +bforce/expression.l.o: bforce/expression.y.c bforce/expression.l.c + +installdirs: + if [ ! -d $(CONFDIR) ]; then mkdir -p $(CONFDIR); fi + if [ ! -d $(BINDIR) ]; then mkdir -p $(BINDIR); fi + if [ ! -d $(LOGDIR) ]; then mkdir -p $(LOGDIR); fi + if [ ! -d $(SPOOLDIR) ]; then mkdir -p $(SPOOLDIR); fi + if [ ! -d $(SPOOLDIR)/bt/in ]; then mkdir -p $(SPOOLDIR)/bt/in; fi + if [ ! -d $(SPOOLDIR)/bt/pin ]; then mkdir -p $(SPOOLDIR)/bt/pin; fi + if [ ! -d $(SPOOLDIR)/bt/out ]; then mkdir -p $(SPOOLDIR)/bt/out; fi + if [ ! -d $(SPOOLDIR)/ndl ]; then mkdir -p $(SPOOLDIR)/ndl; fi + if [ ! -d $(SPOOLDIR)/bforce ]; then mkdir -p $(SPOOLDIR); fi + chown $(OWNER).$(GROUP) $(CONFDIR) + chown $(OWNER).$(GROUP) $(LOGDIR) + chown $(OWNER).$(GROUP) $(SPOOLDIR)/bt/in + chown $(OWNER).$(GROUP) $(SPOOLDIR)/bt/pin + chown $(OWNER).$(GROUP) $(SPOOLDIR)/bt/out + chown $(OWNER).$(GROUP) $(SPOOLDIR)/ndl + chown $(OWNER).$(GROUP) $(SPOOLDIR) + +install: + $(INSTALL_PROGRAM) -o $(OWNER) -g $(GROUP) $(SRCDIR)/bin/bforce $(BINDIR)/bforce + $(INSTALL_PROGRAM) -o $(OWNER) -g $(GROUP) $(SRCDIR)/bin/bfindex $(BINDIR)/bfindex + $(INSTALL_PROGRAM) -o $(OWNER) -g $(GROUP) $(SRCDIR)/bin/bfstat $(BINDIR)/bfstat + $(INSTALL_PROGRAM) -o $(OWNER) -g $(GROUP) $(SRCDIR)/bin/nlookup $(BINDIR)/nlookup + $(INSTALL_PROGRAM) -o $(OWNER) -g $(GROUP) $(CONTRIBDIR)/outman $(BINDIR)/outman + $(INSTALL_DATA) -o $(OWNER) -g $(GROUP) $(SRCDIRCONF)/bforce.conf $(CONFDIR)/bforce.conf.sample + $(INSTALL_DATA) -o $(OWNER) -g $(GROUP) $(SRCDIRCONF)/bforce.subst $(CONFDIR)/bforce.subst.sample + $(INSTALL_DATA) -o $(OWNER) -g $(GROUP) $(SRCDIRCONF)/bforce.passwd $(CONFDIR)/bforce.passwd.sample + $(INSTALL_DATA) -o $(OWNER) -g $(GROUP) $(SRCDIRCONF)/freq.aliases $(CONFDIR)/freq.aliases.sample + $(INSTALL_DATA) -o $(OWNER) -g $(GROUP) $(SRCDIRCONF)/freq.dirs $(CONFDIR)/freq.dirs.sample + @echo "Please, edit $(BINDIR)/outman" diff --git a/source/Makefile.in b/source/Makefile.in new file mode 100644 index 0000000..0c6ab5d --- /dev/null +++ b/source/Makefile.in @@ -0,0 +1,185 @@ +# +# Copyright (c) 1999-2000, Alexander Belkin +# +# $Id$ +# + +CC = @CC@ +INCLUDES = -I./include +CFLAGS = @CFLAGS@ +LIBS = @LIBS@ +YACC = @YACC@ +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +SRCDIR = @srcdir@ +SRCDIRCONF = $(SRCDIR)/../examples +CONTRIBDIR = $(SRCDIR)/../contrib + +OWNER = @OWNER@ +GROUP = @GROUP@ +CONFDIR = @prefix@/etc +BINDIR = @prefix@/bin +LOGDIR = /var/log/bforce +SPOOLDIR = /var/spool/bforce + +DAEMON_LOGFILE = $(LOGDIR)/bf-daemon +BFORCE_LOGFILE = $(LOGDIR)/bf-log +BFORCE_DEBFILE = $(LOGDIR)/bf-debug +BFORCE_CFGFILE = $(CONFDIR)/bforce.conf + +DEFINES = -DDAEMON_LOGFILE=\"$(DAEMON_LOGFILE)\" \ + -DBFORCE_LOGFILE=\"$(BFORCE_LOGFILE)\" \ + -DBFORCE_DEBFILE=\"$(BFORCE_DEBFILE)\" \ + -DBFORCE_CFGFILE=\"$(BFORCE_CFGFILE)\" \ + -DBF_OS=\"@build_os@\" @DEFS@ + +SUBDIRS = bforce bfutil + +BFINDEX_OBJS = bfutil/bfindex.o \ + bforce/conf_deinit.o bforce/conf_proc.o \ + bforce/conf_read.o bforce/conf_get.o \ + bforce/logger.o bforce/nodelist.o \ + bforce/u_file.o bforce/u_ftn.o \ + bforce/u_misc.o bforce/u_string.o \ + bforce/u_time.o + +NLOOKUP_OBJS = bfutil/nlookup.o \ + bforce/conf_deinit.o bforce/conf_proc.o \ + bforce/conf_read.o bforce/conf_get.o \ + bforce/logger.o bforce/nodelist.o \ + bforce/u_file.o bforce/u_ftn.o \ + bforce/u_misc.o bforce/u_string.o \ + bforce/u_time.o + +BFSTAT_OBJS = bfutil/bfstat.o \ + bforce/conf_deinit.o bforce/conf_proc.o \ + bforce/conf_read.o bforce/conf_get.o \ + bforce/outb_flo.o bforce/outb_fsqueue.o \ + bforce/sess_stat.o \ + bforce/outb_getname.o bforce/outb_sysqueue.o \ + bforce/outb_scan.o bforce/logger.o \ + bforce/u_file.o \ + bforce/u_ftn.o bforce/u_misc.o \ + bforce/u_string.o bforce/u_time.o \ + bforce/u_plock.o + +BFORCE_OBJS = bforce/bforce.o \ + bforce/daemon.o bforce/daemon_branch.o \ + bforce/daemon_call.o bforce/daemon_lines.o \ + bforce/conf_deinit.o \ + bforce/conf_proc.o bforce/conf_read.o \ + bforce/conf_get.o bforce/expression.o \ + bforce/freq_bark.o bforce/freq_proc.o \ + bforce/freq_srif.o bforce/freq_wazoo.o \ + bforce/io_modem.o bforce/io_tcpip.o \ + bforce/io_unix_lock.o bforce/io_unix_modem.o \ + bforce/io_unix_tio.o bforce/io_unix_tty.o \ + bforce/logger.o bforce/nodelist.o \ + bforce/os_unix.o bforce/outb_bsy.o \ + bforce/outb_flo.o bforce/outb_fsqueue.o \ + bforce/outb_getname.o bforce/outb_sysqueue.o \ + bforce/outb_scan.o bforce/prot_common.o \ + bforce/prot_binkp.o bforce/prot_binkp_api.o \ + bforce/prot_binkp_misc.o bforce/prot_hydra.o \ + bforce/prot_xmrecv.o bforce/prot_xmsend.o \ + bforce/prot_zmmisc.o bforce/prot_zmrecv.o \ + bforce/prot_zmsend.o \ + bforce/prot_yoohoo.o bforce/prot_yoohoo_api.o \ + bforce/prot_emsi.o bforce/prot_emsi_misc.o \ + bforce/prot_emsi_api.o \ + bforce/sess_common.o bforce/sess_stat.o \ + bforce/sess_call.o bforce/sess_answ.o \ + bforce/sess_init.o bforce/sess_main.o \ + bforce/u_crc.o bforce/u_ftn.o \ + bforce/u_md5.o \ + bforce/u_misc.o bforce/u_string.o \ + bforce/u_time.o bforce/u_file.o \ + bforce/u_pkt.o bforce/u_recode.o \ + bforce/u_plock.o + +.c.o: + @echo Compiling $*.c + @$(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) -c $< -o $@ + +all: bin/bforce bin/bfindex bin/bfstat bin/nlookup + +expression.c: bforce/expression.y + $(YACC) bforce/expression.y + mv y.tab.c bforce/expression.c + +bin/bforce: $(BFLIB_OBJS) $(BFORCE_OBJS) + @echo "Linking $@" + @$(CC) $(BFLIB_OBJS) $(BFORCE_OBJS) $(LIBS) -o $@ + +bin/bfindex: $(BFLIB_OBJS) $(BFINDEX_OBJS) + @echo "Linking $@" + @$(CC) $(BFLIB_OBJS) $(BFINDEX_OBJS) $(LIBS) -o $@ + +bin/nlookup: $(BFLIB_OBJS) $(NLOOKUP_OBJS) + @echo "Linking $@" + @$(CC) $(BFLIB_OBJS) $(NLOOKUP_OBJS) $(LIBS) -o $@ + +bin/bfstat: $(BFLIB_OBJS) $(BFSTAT_OBJS) + @echo "Linking $@" + @$(CC) $(BFLIB_OBJS) $(BFSTAT_OBJS) $(LIBS) -o $@ + + +clean: + @for i in $(SUBDIRS); do (rm -f $$i/*.o || exit 1); done + rm -f ./bforce/expression.c + rm -f ./bin/bforce + rm -f ./bin/bfindex + rm -f ./bin/bfstat + rm -f ./bin/nlookup + rm -f ./bin/core +clean-am: + rm -f ./Makefile + rm -f ./include/config.h + rm -f ./config.log + rm -f ./config.status +clean-ac: + rm -f ./configure + +distclean: clean clean-am + +distclean-m: distclean clean-ac + + +ifnames: + @for i in $(SUBDIRS); do (ifnames $$i/*.c || exit 1); done + +bforce/expression.y.o: bforce/expression.y.c bforce/expression.l.c + +bforce/expression.l.o: bforce/expression.y.c bforce/expression.l.c + +installdirs: + if [ ! -d $(CONFDIR) ]; then mkdir -p $(CONFDIR); fi + if [ ! -d $(BINDIR) ]; then mkdir -p $(BINDIR); fi + if [ ! -d $(LOGDIR) ]; then mkdir -p $(LOGDIR); fi + if [ ! -d $(SPOOLDIR) ]; then mkdir -p $(SPOOLDIR); fi + if [ ! -d $(SPOOLDIR)/bt/in ]; then mkdir -p $(SPOOLDIR)/bt/in; fi + if [ ! -d $(SPOOLDIR)/bt/pin ]; then mkdir -p $(SPOOLDIR)/bt/pin; fi + if [ ! -d $(SPOOLDIR)/bt/out ]; then mkdir -p $(SPOOLDIR)/bt/out; fi + if [ ! -d $(SPOOLDIR)/ndl ]; then mkdir -p $(SPOOLDIR)/ndl; fi + if [ ! -d $(SPOOLDIR)/bforce ]; then mkdir -p $(SPOOLDIR); fi + chown $(OWNER).$(GROUP) $(CONFDIR) + chown $(OWNER).$(GROUP) $(LOGDIR) + chown $(OWNER).$(GROUP) $(SPOOLDIR)/bt/in + chown $(OWNER).$(GROUP) $(SPOOLDIR)/bt/pin + chown $(OWNER).$(GROUP) $(SPOOLDIR)/bt/out + chown $(OWNER).$(GROUP) $(SPOOLDIR)/ndl + chown $(OWNER).$(GROUP) $(SPOOLDIR) + +install: + $(INSTALL_PROGRAM) -o $(OWNER) -g $(GROUP) $(SRCDIR)/bin/bforce $(BINDIR)/bforce + $(INSTALL_PROGRAM) -o $(OWNER) -g $(GROUP) $(SRCDIR)/bin/bfindex $(BINDIR)/bfindex + $(INSTALL_PROGRAM) -o $(OWNER) -g $(GROUP) $(SRCDIR)/bin/bfstat $(BINDIR)/bfstat + $(INSTALL_PROGRAM) -o $(OWNER) -g $(GROUP) $(SRCDIR)/bin/nlookup $(BINDIR)/nlookup + $(INSTALL_PROGRAM) -o $(OWNER) -g $(GROUP) $(CONTRIBDIR)/outman $(BINDIR)/outman + $(INSTALL_DATA) -o $(OWNER) -g $(GROUP) $(SRCDIRCONF)/bforce.conf $(CONFDIR)/bforce.conf.sample + $(INSTALL_DATA) -o $(OWNER) -g $(GROUP) $(SRCDIRCONF)/bforce.subst $(CONFDIR)/bforce.subst.sample + $(INSTALL_DATA) -o $(OWNER) -g $(GROUP) $(SRCDIRCONF)/bforce.passwd $(CONFDIR)/bforce.passwd.sample + $(INSTALL_DATA) -o $(OWNER) -g $(GROUP) $(SRCDIRCONF)/freq.aliases $(CONFDIR)/freq.aliases.sample + $(INSTALL_DATA) -o $(OWNER) -g $(GROUP) $(SRCDIRCONF)/freq.dirs $(CONFDIR)/freq.dirs.sample + @echo "Please, edit $(BINDIR)/outman" diff --git a/source/bforce/bforce.c b/source/bforce/bforce.c new file mode 100644 index 0000000..6713abc --- /dev/null +++ b/source/bforce/bforce.c @@ -0,0 +1,485 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "version.h" +#include "logger.h" +#include "util.h" +#include "bforce.h" +#include "nodelist.h" +#include "session.h" + +/* PID of our child process (if use fork) */ +pid_t child_pid = 0; + +const char *BFERR[] = { + /* 00 */ "Successfull", + /* 01 */ "Fatal error occured", + /* 02 */ "Unknown phone number(or ip address)", + /* 03 */ "Modem port busy (or open error)", + /* 04 */ "System locked now", + /* 05 */ "Try later", + /* 06 */ "Modem not response", + /* 07 */ "Not working now", + /* 08 */ "Unused entry", + /* 09 */ "Unused entry", + /* 10 */ "Can't connect to remote", + /* 11 */ "Can't connect to remote: busy", + /* 12 */ "Can't connect to remote: nocarrier", + /* 13 */ "Can't connect to remote: nodialtone", + /* 14 */ "Can't connect to remote: noanswer", + /* 15 */ "Can't connect to remote: error", + /* 16 */ "Can't connect to remote: user defined 16", + /* 17 */ "Can't connect to remote: user defined 17", + /* 18 */ "Can't connect to remote: user defined 18", + /* 19 */ "Can't connect to remote: user defined 19", + /* 20 */ "Connect speed too low", + /* 21 */ "Cannot handshake with remote", + /* 22 */ "Xmiting error", + /* 23 */ "CPS too low", + /* 24 */ "Reached stop time", + /* 25 */ "Unused entry", + /* 26 */ "Unused entry", + /* 27 */ "Unused entry" +}; + +static void deinit_opts(s_bforce_opts *opts); + +/* +static void print_compiled_configuration(void) +{ + printf("BFORCE_LOGFILE = "BFORCE_LOGFILE"\n"); + printf("BFORCE_DEBFILE = "BFORCE_DEBFILE"\n"); + printf("DAEMON_LOGFILE = "DAEMON_LOGFILE"\n"); + printf("BFORCE_CFGFILE = "BFORCE_CFGFILE"\n"); + printf("BF_OS = "BF_OS"\n"); +} +*/ + +static void usage(void) +{ + printf_usage(NULL, + "usage: bforce [-fmh] [-I] [-n] [-l]\n" + " [-a] [-S] [-p] \n" + " bforce [-ih] [-I] [-S]\n" + " (this implies slave mode)\n" + " bforce [-dh] [-C] [-I]\n" + "\n" + "options:\n" + " -d run as daemon\n" + " -q terminate daemon\n" + " -i run from inetd (for slave mode only)\n" + " -f ignore system's work time\n" + " -o starts outgoing session on stdin/stdout\n" + " -C main config file name (\"%s\")\n" + " -I additional config file name\n" + " -n override phone number\n" + " -l call on this hidden line (default is 0) \n" + " -a override internet address\n" + " -S connect string (for slave mode only)\n" + " -p override modem port (must be defined in config)\n" + " -h show this help message\n" + "\n", + conf_getconfname() + ); +} + +int bforce_create_dirs(void) +{ + const char *p_dirname = conf_string(cf_status_directory); + + if( p_dirname ) + { + if( access(p_dirname, F_OK) == -1 || !is_directory(p_dirname) ) + { + if( directory_create(p_dirname, 0700) == -1 ) + { + logerr("cannot create spool directory \"%s\"", p_dirname); + return -1; + } + } + } + + return 0; +} + +/* + * Universal signal handler for parent processes :) Will resend + * signals to child process + */ +static RETSIGTYPE parent_sighandler(int sig) +{ + /* Send this signal to our child */ + if( child_pid ) kill(child_pid, sig); +} + +/* + * Return non-zero value to indicate error, on success - return zero + * to child process and NEVER return to parent process + */ +static int usefork(void) +{ + pid_t cpid; /* child PID */ + pid_t wpid; /* waitpid() returned value */ + int status = 0; + + cpid = fork(); + + if( cpid == 0 ) + { return 0; } + + if( cpid < 0 ) + { logerr("failed fork() call"); return 1; } + + /* + * Now we are parent process + */ + + /* Put PID into global variable */ + child_pid = cpid; + + /* Setup signals handling */ + signal(SIGHUP, parent_sighandler); + signal(SIGINT, parent_sighandler); + signal(SIGTERM, parent_sighandler); + signal(SIGUSR1, parent_sighandler); + signal(SIGUSR2, parent_sighandler); + + /* Wait until child die */ + while( (wpid = waitpid(cpid, &status, 0)) < 0 && errno == EINTR ) + { + /* EMPTY LOOP */ + } + + if( wpid == cpid && WIFEXITED(status) ) + { + /* Child was terminated with _exit() */ + exit(WEXITSTATUS(status)); + } + else if( wpid < 0 && WIFSIGNALED(status) ) + { + /* Child was terminated by signal */ + kill(getpid(), WTERMSIG(status)); + } + exit(BFERR_FATALERROR); +} + +static int bforce_master(const s_bforce_opts *opts) +{ + s_falist *tmpl; + int rc, maxrc = BFERR_NOERROR; + +#ifdef GETPGRP_VOID + if( getpgrp() == getpid() ) +#else + if( getpgrp(0) == getpid() ) +#endif + { + /* We are process group leader -> fork() */ + if( usefork() ) return BFERR_FATALERROR; + } + + for( tmpl = opts->addrlist; tmpl; tmpl = tmpl->next ) + { + int callopt = 0; + + if( opts->iaddr ) callopt |= CALLOPT_INET; + if( opts->force ) callopt |= CALLOPT_FORCE; + + rc = call_system(tmpl->addr, opts); + + if( rc > maxrc ) maxrc = rc; + } + + return maxrc; +} + +static int bforce_slave(const s_bforce_opts *opts) +{ + return answ_system(opts->stype, opts->connect, opts->inetd); +} + +static int bforce_daemon(const s_bforce_opts *opts) +{ + int forkrc = fork(); + + if( forkrc == -1 ) + { + logerr("cannot run daemon: failed fork() call"); + return BFERR_FATALERROR; + } + else if( forkrc > 0 ) + { + return BFERR_NOERROR; + } + + /* + * We are inside a child process. + * Create new session and run daemon + */ + setsid(); + + return daemon_run(opts->confname, opts->incname, opts->quit); +} + +int main(int argc, char *argv[], char *envp[]) +{ + s_bforce_opts opts; + int rc = 0; + int ch = 0; + int role = 0; + + memset(&opts, '\0', sizeof(s_bforce_opts)); + + while( (ch=getopt(argc, argv, "hodqr:ifC:I:n:l:a:S:p:")) != EOF ) + { + switch( ch ) { + case 'h': + usage(); + exit(BFERR_NOERROR); + case 'd': + if( opts.inetd || opts.force || opts.phone + || opts.hiddline || opts.iaddr || opts.connect + || opts.device || opts.quit ) + { usage(); exit(BFERR_FATALERROR); } + else + { opts.daemon = 1; } + break; + case 'q': + if( opts.inetd || opts.force || opts.phone + || opts.hiddline || opts.iaddr || opts.connect + || opts.device || opts.daemon ) + { usage(); exit(BFERR_FATALERROR); } + else + { opts.daemon = 1; opts.quit = 1; } + break; + case 'i': + if( opts.daemon ) + { usage(); exit(BFERR_FATALERROR); } + else + { opts.inetd = 1; } + break; + case 'f': + if( opts.daemon ) + { usage(); exit(BFERR_FATALERROR); } + else + { opts.force = 1; } + break; + case 'o': + if( opts.dontcall ) + { usage(); exit(BFERR_FATALERROR); } + else + { opts.dontcall = TRUE; } + break; + case 'C': + if( opts.confname ) free(opts.confname); + if( optarg ) opts.confname = (char *)xstrcpy(optarg); + break; + case 'I': + if( opts.incname ) free(opts.incname); + if( optarg ) opts.incname = (char *)xstrcpy(optarg); + break; + case 'n': + if( opts.daemon ) + { usage(); exit(BFERR_FATALERROR); } + else + { + if( opts.phone ) free(opts.phone); + if( optarg ) opts.phone = (char *)xstrcpy(optarg); + } + break; + case 'l': + if( ISDEC(optarg) && opts.daemon == 0 ) + opts.hiddline = atoi(optarg); + else + { usage(); exit(BFERR_FATALERROR); } + break; + case 'a': + if( opts.daemon ) + { usage(); exit(BFERR_FATALERROR); } + else + { + if( opts.iaddr ) free(opts.iaddr); + if( optarg ) opts.iaddr = (char *)xstrcpy(optarg); + } + break; + case 'S': + if( opts.daemon ) + { usage(); exit(BFERR_FATALERROR); } + else + { + if( opts.connect ) free(opts.connect); + if( optarg ) opts.connect = (char *)xstrcpy(optarg); + } + break; + case 'p': + if( opts.daemon ) + { usage(); exit(BFERR_FATALERROR); } + else + { + if( opts.device ) free(opts.device); + if( optarg ) opts.device = (char *)xstrcpy(optarg); + } + break; + default : + usage(); + exit(BFERR_FATALERROR); + } + } + + /* Expression checker use it, so init first */ + init_state(&state); + + /* Set space available for process title */ +#ifndef HAVE_SETPROCTITLE + setargspace(argv, envp); +#endif + + /* Initialise random number generation */ + (void)srand((unsigned)time(NULL)); + + /* Initialise current locale */ + (void)setlocale(LC_ALL, ""); + + /* Set secure process umask */ + (void)umask(~(S_IRUSR|S_IWUSR)); + + /* Now process non-option arguments */ + if( opts.daemon == FALSE ) + { + const char *p; + s_faddr addr; + s_falist **alist = &opts.addrlist; + + while( (optind < argc) && (p = argv[optind++]) ) + { + for( ; *p == '*'; p++ ); + + if( strcasecmp(p, "tsync") == 0 ) + { + role = 0; + opts.stype = SESSION_FTSC; + } + else if( strcasecmp(p, "yoohoo") == 0 ) + { + role = 0; + opts.stype = SESSION_YOOHOO; + } + else if( strcasecmp(p, "**EMSI_INQC816") == 0 ) + { + role = 0; + opts.stype = SESSION_EMSI; + } + else if( strncasecmp(p, "emsi", 4) == 0 ) + { + role = 0; + opts.stype = SESSION_EMSI; + } + else if( strcasecmp(p, "binkp") == 0 ) + { + role = 0; + opts.stype = SESSION_BINKP; + } + else if( strcasecmp(p, "auto") == 0 ) + { + role = 0; + opts.stype = SESSION_UNKNOWN; + } + else if( ftn_addrparse(&addr, p, FALSE) == 0 ) + { + role = 1; + (*alist) = (s_falist*)xmalloc(sizeof(s_falist)); + memset(*alist, '\0', sizeof(s_falist)); + (*alist)->addr = addr; + alist = &(*alist)->next; + } + else + { + printf("invalid address \"%s\"", p); + usage(); + exit(BFERR_FATALERROR); + } + } + + if( opts.dontcall && role == 0 ) + { + usage(); + exit(BFERR_FATALERROR); + } + } + +/* if( (rc = log_open(log_getfilename(LOG_FILE_SESSION), NULL, NULL)) ) + { + log("can't continue without logging"); + gotoexit(BFERR_FATALERROR); + } +*/ + /* Process primary config file */ + if( opts.confname && *opts.confname ) + rc = conf_readconf(opts.confname, 0); + else + rc = conf_readconf(conf_getconfname(), 0); + + if( rc ) gotoexit(BFERR_FATALERROR); + + /* Process additional config file, ignore errors */ + if( opts.incname && *opts.incname ) + (void)conf_readconf(opts.incname, 1); + + /* Reopen log file if it was defined in config */ + if( log_open(log_getfilename(LOG_FILE_SESSION), NULL, NULL) ) + { + log("can't continue without logging"); + gotoexit(BFERR_FATALERROR); + } + +#ifdef DEBUG + /* Same for the debug file */ + (void)debug_setfilename(log_getfilename(LOG_FILE_DEBUG)); +#endif + + if( opts.daemon ) + rc = bforce_daemon(&opts); + else if( role ) + rc = bforce_master(&opts); + else + rc = bforce_slave(&opts); + +exit: + + deinit_conf(); + deinit_opts(&opts); + + /* Shutdown logging services */ + if( log_isopened() ) log_close(); +#ifdef DEBUG + if( debug_isopened() ) debug_close(); +#endif + + exit(rc); +} + +static void deinit_opts(s_bforce_opts *opts) +{ + if( opts->confname ) free(opts->confname); + if( opts->incname ) free(opts->incname); + if( opts->phone ) free(opts->phone); + if( opts->iaddr ) free(opts->iaddr); + if( opts->connect ) free(opts->connect); + if( opts->device ) free(opts->device); + if( opts->addrlist ) deinit_falist(opts->addrlist); + + memset(opts, '\0', sizeof(s_bforce_opts)); +} + diff --git a/source/bforce/conf_deinit.c b/source/bforce/conf_deinit.c new file mode 100644 index 0000000..530ecd3 --- /dev/null +++ b/source/bforce/conf_deinit.c @@ -0,0 +1,135 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + + +void deinit_conf(void) +{ + s_cval_entry *ptrl; + s_cval_entry *next; + int i; + + for( i = 0; bforce_config[i].name; i++ ) + { + for( ptrl = bforce_config[i].data; ptrl; ptrl = next ) + { + next = ptrl->next; + deinit_cval_entry(ptrl, bforce_config[i].type); + free(ptrl); + } + bforce_config[i].data = NULL; + } +} + +void deinit_cval_entry(s_cval_entry *dest, bforce_config_keyword type) +{ + /* + * Other config variables doesn't use allocated memory + */ + switch(type) { + case CT_ADDRESS: + case CT_NODELIST: + case CT_PASSWORD: + if( dest->d.falist.what ) + free(dest->d.falist.what); + break; + case CT_DOMAIN: + deinit_domain(&dest->d.domain); + break; + case CT_DIALRESP: + deinit_dialresp(&dest->d.dialresp); + break; + case CT_MODEMPORT: + deinit_modemport(&dest->d.modemport); + break; + case CT_OVERRIDE: + deinit_override(&dest->d.override); + break; + case CT_PATH: + case CT_STRING: + deinit_string(&dest->d.string); + break; + case CT_TRANSLATE: + deinit_translate(&dest->d.translate); + break; + default: + DEB((D_CONFIG, "deinit_cval_entry: type %d doesn't use dynamic memory", + type)); + } +} + +void deinit_dialresp(s_dialresp *dest) +{ + if( dest->mstr ) free(dest->mstr); +} + +void deinit_domain(s_domain *dest) +{ + if( dest->domain ) free(dest->domain); + if( dest->path ) free(dest->path); +} + +void deinit_expr(s_expr *dest) +{ + if( dest->expr ) free(dest->expr); +} + +void deinit_falist(s_falist *dest) +{ + s_falist *ptrl, *next; + + for( ptrl = dest; ptrl; ptrl = next ) + { + next = ptrl->next; + if( ptrl->what ) free(ptrl->what); + free(ptrl); + } +} + +void deinit_modemport(s_modemport *dest) +{ + if( dest->name ) free(dest->name); +} + +void deinit_override(s_override *dest) +{ + s_override *ptrl, *next; + + if( dest->sIpaddr ) free(dest->sIpaddr); + if( dest->sPhone ) free(dest->sPhone); + if( dest->sFlags ) free(dest->sFlags); + for( ptrl = dest->hidden; ptrl; ptrl = next ) + { + next = ptrl->hidden; + if( ptrl->sIpaddr ) free(ptrl->sIpaddr); + if( ptrl->sPhone ) free(ptrl->sPhone); + if( ptrl->sFlags ) free(ptrl->sFlags); + free(ptrl); + } +} + +void deinit_string(s_string *dest) +{ + if( dest->str ) free(dest->str); +} + +void deinit_translate(s_translate *dest) +{ + if( dest->find ) free(dest->find); + if( dest->repl ) free(dest->repl); +} + diff --git a/source/bforce/conf_get.c b/source/bforce/conf_get.c new file mode 100644 index 0000000..2974e1a --- /dev/null +++ b/source/bforce/conf_get.c @@ -0,0 +1,108 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +s_cval_entry *conf_first(bforce_config_keyword keyword) +{ + s_cval_entry *ptrl; + + for( ptrl = bforce_config[keyword].data; ptrl; ptrl = ptrl->next ) + if( !ptrl->expr.expr || eventexpr(&ptrl->expr) ) + return ptrl; + + return NULL; +} + +s_cval_entry *conf_next(s_cval_entry *ptrl) +{ + ASSERT(ptrl); + + for( ptrl = ptrl->next; ptrl; ptrl = ptrl->next ) + if( !ptrl->expr.expr || eventexpr(&ptrl->expr) ) + return ptrl; + + return NULL; +} + +bool conf_boolean(bforce_config_keyword keyword) +{ + s_cval_entry *ptrl = conf_first(keyword); + + return ptrl ? ptrl->d.boolean.istrue : FALSE; +} + +mode_t conf_filemode(bforce_config_keyword keyword) +{ + s_cval_entry *ptrl = conf_first(keyword); + + return ptrl ? ptrl->d.filemode.mode : (mode_t)0; +} + +long conf_options(bforce_config_keyword keyword) +{ + long result = 0L; + s_cval_entry *ptrl; + + for( ptrl = conf_first(keyword); ptrl; ptrl = conf_next(ptrl) ) + result = ((~ptrl->d.options.mask) & result) | ptrl->d.options.value; + + return result; +} + +long conf_connlist(bforce_config_keyword keyword, long speed) +{ + s_cval_entry *ptrl; + + for( ptrl = conf_first(keyword); ptrl; ptrl = conf_next(ptrl) ) + if( ptrl->d.connlist.speed == speed ) + return ptrl->d.connlist.value; + + return 0; +} + +char *conf_string(bforce_config_keyword keyword) +{ + s_cval_entry *ptrl = conf_first(keyword); + + return ptrl ? ptrl->d.string.str : (char*)NULL; +} + +long conf_number(bforce_config_keyword keyword) +{ + s_cval_entry *ptrl = conf_first(keyword); + + return ptrl ? ptrl->d.number.num : (long)0L; +} + +s_override *conf_override(bforce_config_keyword keyword, s_faddr addr) +{ + s_cval_entry *ptrl; + + for( ptrl = conf_first(keyword); ptrl; ptrl = conf_next(ptrl) ) + if( !ftn_addrcomp(ptrl->d.override.addr, addr) ) + return &ptrl->d.override; + + return NULL; +} + +s_tries *conf_tries(bforce_config_keyword keyword) +{ + s_cval_entry *ptrl = conf_first(keyword); + + return ptrl ? &ptrl->d.tries : NULL; +} + diff --git a/source/bforce/conf_proc.c b/source/bforce/conf_proc.c new file mode 100644 index 0000000..2bafc81 --- /dev/null +++ b/source/bforce/conf_proc.c @@ -0,0 +1,997 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "outbound.h" /* Required only for ``proc_filebox()'' */ + +struct tab_options { +const char *keystr; + unsigned long value_no; + unsigned long value_yes; +} options[] = { + { "Zmodem", OPTIONS_NO_ZMODEM, 0 }, + { "ZedZap", OPTIONS_NO_ZEDZAP, 0 }, + { "DirZap", OPTIONS_NO_DIRZAP, 0 }, + { "Janus", OPTIONS_NO_JANUS, 0 }, + { "Hydra", OPTIONS_NO_HYDRA, 0 }, + { "BinkP", OPTIONS_NO_BINKP, 0 }, + { "TCP", OPTIONS_NO_TCP, 0 }, + { "Chat", OPTIONS_NO_CHAT, 0 }, + { "FTS1", OPTIONS_NO_FTS1, 0 }, + { "YooHoo", OPTIONS_NO_YOOHOO, 0 }, + { "EMSI", OPTIONS_NO_EMSI, 0 }, + { "EMSI-II", OPTIONS_NO_EMSI_II, 0 }, + { "Freqs", OPTIONS_NO_FREQS, 0 }, + { "MailOnly", 0, OPTIONS_MAILONLY }, + { "HoldXT" , 0, OPTIONS_HOLDXT }, + { "HoldReq", 0, OPTIONS_HOLDREQ }, + { "HoldAll", 0, OPTIONS_HOLDALL }, + { "HoldHold", 0, OPTIONS_HOLDHOLD }, + { "PickUp", OPTIONS_NO_PICKUP, 0 }, + { "RH1", OPTIONS_NO_RH1, 0 }, + { "Intro", OPTIONS_NO_INTRO, 0 }, + { NULL, 0, 0 } +}; + +struct tab_resptypes { +const char *str; + int value; + int retv; +} resptypes[] = { + { "Connect", RESPTYPE_CONNECT, 0 }, + { "Busy", RESPTYPE_BUSY, 11 }, + { "Nocarrier", RESPTYPE_NOCARRIER, 12 }, + { "Nodialtone", RESPTYPE_NODIALTONE, 13 }, + { "Noanswer", RESPTYPE_NOANSWER, 14 }, + { "Error", RESPTYPE_ERROR, 15 }, + { NULL, 0, 0 } +}; + +#define CONF_KEY(name, type) { #name, type, NULL, cf_##name } +#define CONF_END() { NULL, 0, NULL, 0 } + +s_conf_entry bforce_config[BFORCE_NUMBER_OF_KEYWORDS+1] = { + CONF_KEY(address, CT_ADDRESS), + CONF_KEY(amiga_outbound_directory, CT_PATH), + CONF_KEY(binkp_timeout, CT_NUMBER), + CONF_KEY(daemon_circle, CT_NUMBER), + CONF_KEY(daemon_circle_crash, CT_NUMBER), + CONF_KEY(daemon_circle_direct, CT_NUMBER), + CONF_KEY(daemon_circle_immed, CT_NUMBER), + CONF_KEY(daemon_circle_modem, CT_NUMBER), + CONF_KEY(daemon_circle_normal, CT_NUMBER), + CONF_KEY(daemon_circle_rescan, CT_NUMBER), + CONF_KEY(daemon_maxclients_modem, CT_NUMBER), + CONF_KEY(daemon_maxclients_tcpip, CT_NUMBER), + CONF_KEY(daemon_pid_file, CT_STRING), + CONF_KEY(delay_files_recv, CT_STRING), + CONF_KEY(delay_files_send, CT_STRING), + CONF_KEY(disable_aka_matching, CT_BOOLEAN), + CONF_KEY(domain, CT_DOMAIN), + CONF_KEY(emsi_FR_time, CT_STRING), + CONF_KEY(emsi_OH_time, CT_STRING), + CONF_KEY(emsi_slave_sends_nak, CT_BOOLEAN), + CONF_KEY(filebox, CT_FILEBOX), + CONF_KEY(filebox_directory, CT_PATH), + CONF_KEY(flags, CT_STRING), + CONF_KEY(flo_translate, CT_TRANSLATE), + CONF_KEY(freq_alias_list, CT_STRING), + CONF_KEY(freq_dir_list, CT_STRING), + CONF_KEY(freq_ignore_masks, CT_STRING), + CONF_KEY(freq_limit_number, CT_NUMBER), + CONF_KEY(freq_limit_size, CT_NUMBER), + CONF_KEY(freq_limit_time, CT_NUMBER), + CONF_KEY(freq_min_speed, CT_NUMBER), + CONF_KEY(freq_srif_command, CT_STRING), + CONF_KEY(hide_our_aka, CT_ADDRESS), + CONF_KEY(history_file, CT_STRING), + CONF_KEY(hydra_options, CT_OPTIONS), + CONF_KEY(hydra_mincps_recv, CT_CONNLIST), + CONF_KEY(hydra_mincps_send, CT_CONNLIST), + CONF_KEY(hydra_tx_window, CT_NUMBER), + CONF_KEY(hydra_rx_window, CT_NUMBER), + CONF_KEY(inbound_directory, CT_PATH), + CONF_KEY(location, CT_STRING), + CONF_KEY(log_file, CT_STRING), + CONF_KEY(log_file_daemon, CT_STRING), + CONF_KEY(max_speed, CT_NUMBER), + CONF_KEY(maxtries, CT_TRIES), + CONF_KEY(maxtries_nodial, CT_TRIES), + CONF_KEY(maxtries_noansw, CT_TRIES), + CONF_KEY(maxtries_noconn, CT_TRIES), + CONF_KEY(maxtries_hshake, CT_TRIES), + CONF_KEY(maxtries_sessions, CT_TRIES), + CONF_KEY(min_cps_recv, CT_NUMBER), + CONF_KEY(min_cps_send, CT_NUMBER), + CONF_KEY(min_cps_time, CT_NUMBER), + CONF_KEY(min_free_space, CT_NUMBER), + CONF_KEY(min_speed_in, CT_NUMBER), + CONF_KEY(min_speed_out, CT_NUMBER), + CONF_KEY(mode_netmail, CT_FILEMODE), + CONF_KEY(mode_arcmail, CT_FILEMODE), + CONF_KEY(mode_request, CT_FILEMODE), + CONF_KEY(mode_ticfile, CT_FILEMODE), + CONF_KEY(mode_default, CT_FILEMODE), + CONF_KEY(modem_can_send_break, CT_BOOLEAN), + CONF_KEY(modem_dial_prefix, CT_STRING), + CONF_KEY(modem_dial_suffix, CT_STRING), + CONF_KEY(modem_dial_response, CT_DIALRESP), + CONF_KEY(modem_hangup_command, CT_STRING), + CONF_KEY(modem_port, CT_MODEMPORT), + CONF_KEY(modem_reset_command, CT_STRING), + CONF_KEY(modem_stat_command, CT_STRING), + CONF_KEY(nodelist, CT_NODELIST), + CONF_KEY(nodelist_directory, CT_PATH), + CONF_KEY(nodial_flag, CT_STRING), + CONF_KEY(override, CT_OVERRIDE), + CONF_KEY(options, CT_OPTIONS), + CONF_KEY(outbound_directory, CT_PATH), + CONF_KEY(password, CT_PASSWORD), + CONF_KEY(phone, CT_STRING), + CONF_KEY(phone_translate, CT_TRANSLATE), + CONF_KEY(recode_file_in, CT_STRING), + CONF_KEY(recode_file_out, CT_STRING), + CONF_KEY(recode_intro_in, CT_STRING), + CONF_KEY(recv_buffer_size, CT_NUMBER), + CONF_KEY(rescan_delay, CT_NUMBER), + CONF_KEY(run_after_handshake, CT_STRING), + CONF_KEY(run_after_session, CT_STRING), + CONF_KEY(session_limit_in, CT_NUMBER), + CONF_KEY(session_limit_out, CT_NUMBER), + CONF_KEY(skip_files_recv, CT_STRING), + CONF_KEY(status_directory, CT_PATH), + CONF_KEY(system_name, CT_STRING), + CONF_KEY(sysop_name, CT_STRING), + CONF_KEY(uucp_lock_directory, CT_PATH), + CONF_KEY(wait_carrier_in, CT_NUMBER), + CONF_KEY(wait_carrier_out, CT_NUMBER), + CONF_KEY(zmodem_mincps_recv, CT_CONNLIST), + CONF_KEY(zmodem_mincps_send, CT_CONNLIST), + CONF_KEY(zmodem_send_dummy_pkt, CT_BOOLEAN), + CONF_KEY(zmodem_skip_by_pos, CT_BOOLEAN), + CONF_KEY(zmodem_start_block_size, CT_NUMBER), + CONF_KEY(zmodem_tx_window, CT_NUMBER), + CONF_KEY(nomail_flag, CT_STRING), + CONF_KEY(bind_ip, CT_STRING), +#ifdef USE_SYSLOG + CONF_KEY(syslog_facility, CT_NUMBER), +#endif +#ifdef DEBUG + CONF_KEY(debug_file, CT_STRING), + CONF_KEY(debug_level, CT_DEBLEVEL), +#endif + CONF_END() +}; + +static int proc_override(s_override *dest, char *value); +static int proc_options(s_options *options, char *value); +static int proc_string(s_string *dest, char *value); +static int proc_number(s_number *dest, char *value); +static int proc_filemode(s_filemode *dest, char *value); +static int proc_boolean(s_boolean *dest, char *value); +static int proc_address(s_falist *dest, char *value); +static int proc_nodelist(s_falist *dest, char *value); +static int proc_modemport(s_modemport *dest, char *value); +static int proc_domain(s_domain *dest, char *value); +static int proc_password(s_falist *dest, char *value); +static int proc_path(s_string *dest, char *value); +static int proc_dialresp(s_dialresp *dest, char *value); +static int proc_translate(s_translate *dest, char *value); +static int proc_speeddep(s_connlist *dest, char *value); +static int proc_tries(s_tries *dest, char *value); +#ifdef DEBUG +static int proc_debuglevel(s_number *dest, char *value); +#endif +static int proc_filebox(s_filebox *dest, char *value); + +static int append_config_entry(s_conf_entry *conf_ent, s_cval_entry *cval_entry) +{ + s_cval_entry **ptrl; + + for( ptrl = &conf_ent->data; *ptrl; ptrl = &(*ptrl)->next ); + + *ptrl = (s_cval_entry *)xmalloc(sizeof(s_cval_entry)); + memcpy(*ptrl, cval_entry, sizeof(s_cval_entry)); + + return 0; +} + +int proc_configline(const char *k, const char *e, const char *v) +{ + s_cval_entry temp_value; + int rc = PROC_RC_ABORT; + int i; + char *copy; + + ASSERT(k != NULL && v != NULL ); + + DEB((D_CONFIG, "conf_proc: key \"%s\" expr \"%s\" value \"%s\"", + k, e, v)); + + copy = xstrcpy(v); + + for( i = 0; bforce_config[i].name; i++ ) + if( !strcmp(bforce_config[i].name, k) ) + break; + + if( bforce_config[i].name ) + { + /* + * Make all changes in temp_value structure + */ + memset(&temp_value, '\0', sizeof(s_cval_entry)); + + switch(bforce_config[i].type) { + case CT_ADDRESS: + rc = proc_address(&temp_value.d.falist, copy); + break; + case CT_BOOLEAN: + rc = proc_boolean(&temp_value.d.boolean, copy); + break; + case CT_CONNLIST: + rc = proc_speeddep(&temp_value.d.connlist, copy); + break; + case CT_DIALRESP: + rc = proc_dialresp(&temp_value.d.dialresp, copy); + break; + case CT_DOMAIN: + rc = proc_domain(&temp_value.d.domain, copy); + break; + case CT_FILEMODE: + rc = proc_filemode(&temp_value.d.filemode, copy); + break; + case CT_MODEMPORT: + rc = proc_modemport(&temp_value.d.modemport, copy); + break; + case CT_NODELIST: + rc = proc_nodelist(&temp_value.d.falist, copy); + break; + case CT_NUMBER: + rc = proc_number(&temp_value.d.number, copy); + break; + case CT_OPTIONS: + rc = proc_options(&temp_value.d.options, copy); + break; + case CT_OVERRIDE: + rc = proc_override(&temp_value.d.override, copy); + break; + case CT_PATH: + rc = proc_path(&temp_value.d.string, copy); + break; + case CT_PASSWORD: + rc = proc_password(&temp_value.d.falist, copy); + break; + case CT_STRING: + rc = proc_string(&temp_value.d.string, copy); + break; + case CT_TRANSLATE: + rc = proc_translate(&temp_value.d.translate, copy); + break; + case CT_TRIES: + rc = proc_tries(&temp_value.d.tries, copy); + break; +#ifdef DEBUG + case CT_DEBLEVEL: + rc = proc_debuglevel(&temp_value.d.number, copy); + break; +#endif + case CT_FILEBOX: + rc = proc_filebox(&temp_value.d.filebox, copy); + break; + default: + log("internal error, unknown keyword type = %d", + bforce_config[i].type); + ASSERT(0); + } + + if( rc == PROC_RC_OK || rc == PROC_RC_WARN ) + { + if( e && *e ) + { + temp_value.expr.expr = xstrcpy(e); + temp_value.expr.error = 0; + } + append_config_entry(&bforce_config[i], &temp_value); + } + } + else + { + log("unknown keyword \"%s\"", k); + rc = PROC_RC_IGNORE; + } + + free(copy); + + return rc; +} + +/* + * Line format: Override
[Hidden ] + */ +static int proc_override(s_override *dest, char *value) +{ + s_override **p = &dest; + s_faddr addr; + int rc = PROC_RC_OK; + char *key = NULL; + char *arg = NULL; + char *n = NULL; + char *p_addr = NULL; + bool neednew = FALSE; + + ASSERT(dest != NULL && value != NULL); + + p_addr = string_token(value, &n, NULL, 0); + if( p_addr == NULL || *p_addr == '\0' || ftn_addrparse(&addr, p_addr, FALSE) ) + return(PROC_RC_IGNORE); + + memset(dest, '\0', sizeof(s_override)); + dest->addr = addr; + + while( key || (key = string_token(NULL, &n, NULL, 1)) ) + { + if( (arg = string_token(NULL, &n, NULL, 1)) == NULL || *arg == '\0' ) + { + log("no argument(s) for override \"%s\"", key); + if( rc < PROC_RC_WARN ) + rc = PROC_RC_WARN; + break; + } + + if( neednew ) + { + (*p) = (s_override*)xmalloc(sizeof(s_override)); + memset(*p, '\0', sizeof(s_override)); + (*p)->addr = addr; + neednew = FALSE; + } + + if( strcasecmp(key, "phone") == 0 ) + { + if( (*p)->sPhone ) + free((*p)->sPhone); + (*p)->sPhone = xstrcpy(arg); + key = NULL; + } + else if( strcasecmp(key, "ipaddr") == 0 ) + { + if( (*p)->sIpaddr ) + free((*p)->sIpaddr); + (*p)->sIpaddr = xstrcpy(arg); + key = NULL; + } + else if( strcasecmp(key, "worktime") == 0 ) + { + if( timevec_parse_list(&((*p)->worktime), arg) == -1 ) + { + log("invalid work time \"%s\"", arg); + if( rc < PROC_RC_WARN ) + rc = PROC_RC_WARN; + } + key = NULL; + } + else if( strcasecmp(key, "freqtime") == 0 ) + { + if( timevec_parse_list(&((*p)->freqtime), arg) == -1 ) + { + log("invalid freq time \"%s\"", arg); + if( rc < PROC_RC_WARN ) + rc = PROC_RC_WARN; + } + key = NULL; + } + else if( strcasecmp(key, "flags") == 0 ) + { + if( (*p)->sFlags ) + free((*p)->sFlags); + (*p)->sFlags = xstrcpy(arg); + key = NULL; + } + else if( strcasecmp(key, "hidden") == 0 ) + { + neednew = TRUE; + p = &((*p)->hidden); + key = arg; + } + else + { + log("unknown keyword \"%s\" in override", key); + if( rc < PROC_RC_WARN ) + rc = PROC_RC_WARN; + key = arg; + } + } + + return(rc); +} + +/* + * Line format: Options + */ +static int proc_options(s_options *dest, char *value) +{ + int i, rc = PROC_RC_OK; + char *key = NULL, *n = NULL; + + ASSERT(dest != NULL && value != NULL); + + for( key = string_token(value, &n, NULL, 0); key; + key = string_token(NULL, &n, NULL, 0) ) + { + for( i = 0; options[i].keystr; i++ ) + { + if( strcasecmp(key, options[i].keystr) == 0 ) + { + if( options[i].value_no ) + { + dest->value &= ~options[i].value_no; + dest->mask |= options[i].value_no; + } + if( options[i].value_yes ) + { + dest->value |= options[i].value_yes; + dest->mask |= options[i].value_yes; + } +#ifdef DEBUG + if( options[i].value_no == 0 && options[i].value_yes == 0 ) + ASSERT_MSG(); +#endif + break; + } + else if( (strncasecmp(key, "no", 2) == 0 + && strcasecmp(key+2, options[i].keystr) == 0) + || (*key == '!' + && strcasecmp(key+1, options[i].keystr) == 0) ) + { + if( options[i].value_no ) + { + dest->value |= options[i].value_no; + dest->mask |= options[i].value_no; + } + if( options[i].value_yes ) + { + dest->value &= ~options[i].value_yes; + dest->mask |= options[i].value_yes; + } +#ifdef DEBUG + if( !options[i].value_no && !options[i].value_yes ) + ASSERT_MSG(); +#endif + break; + } + } + + if( !options[i].keystr ) + { + log("unknown option \"%s\"", key); + if( rc < PROC_RC_WARN ) + rc = PROC_RC_WARN; + } + } + + return(rc); +} + +/* + * Line format: + */ +static int proc_string(s_string *dest, char *value) +{ + ASSERT(dest != NULL && value != NULL); + + dest->str = xstrcpy(value); + + return PROC_RC_OK; +} + +/* + * Line format: + */ +static int proc_number(s_number *dest, char *value) +{ + ASSERT(dest != NULL && value != NULL); + + if( !ISDEC(value) ) + { + log("value \"%s\" isn't numeric", value); + return(PROC_RC_IGNORE); + } + + dest->num = atol(value); + + return(PROC_RC_OK); +} + +/* + * Line format: + */ +static int proc_filemode(s_filemode *dest, char *value) +{ + int rc = PROC_RC_OK; + + ASSERT(dest != NULL && value != NULL); + + if( !ISOCT(value) ) + { + log("value \"%s\" isn't octal number", value); + return(PROC_RC_IGNORE); + } + + sscanf(value, "%o", (unsigned int *)&dest->mode); + + return(rc); +} + +/* + * Line format: + */ +static int proc_boolean(s_boolean *dest, char *value) +{ + ASSERT(dest != NULL && value != NULL); + + if( !strcasecmp(value, "yes") + || !strcasecmp(value, "true") ) + { + dest->istrue = 1; + return(PROC_RC_OK); + } + else if( !strcasecmp(value, "no") + || !strcasecmp(value, "false") ) + { + dest->istrue = 0; + return(PROC_RC_OK); + } + + log("unexpected argument \"%s\", must be \"Yes\" or \"No\"", value); + + return(PROC_RC_IGNORE); +} + +/* + * Line format: + */ +static int proc_address(s_falist *dest, char *value) +{ + s_faddr addr; + + ASSERT(dest != NULL && value != NULL); + + if( ftn_addrparse(&addr, value, FALSE) ) + { + log("can't parse address \"%s\"", value); + return(PROC_RC_IGNORE); + } + + dest->addr = addr; + + return(PROC_RC_OK); +} + +/* + * Line format:
+ */ +static int proc_nodelist(s_falist *dest, char *value) +{ + s_faddr addr; + char *n = NULL; + char *p_name = NULL; + char *p_addr = NULL; + + ASSERT(dest != NULL && value != NULL); + + p_name = string_token(value, &n, NULL, 1); + p_addr = string_token(NULL, &n, NULL, 1); + + if( p_name && *p_name && p_addr && *p_addr ) + { + if( ftn_addrparse(&addr, p_addr, TRUE) == 0 ) + { + dest->addr = addr; + dest->what = xstrcpy(p_name); + return(PROC_RC_OK); + } + else + { + log("can't parse address \"%s\"", p_addr); + return(PROC_RC_IGNORE); + } + } + + log("incorrect nodelist specification"); + return(PROC_RC_IGNORE); +} + +/* + * Line format: + */ +static int proc_domain(s_domain *dest, char *value) +{ + char *n = NULL; + char *p_domn = NULL; + char *p_path = NULL; + char *p_zone = NULL; + + ASSERT(dest != NULL && value != NULL); + + p_domn = string_token(value, &n, NULL, 1); + p_path = string_token(NULL, &n, NULL, 1); + p_zone = string_token(NULL, &n, NULL, 1); + + if( p_domn && *p_domn && p_path && *p_path && p_zone && *p_zone ) + { + if( ISDEC(p_zone) ) + { + dest->domain = xstrcpy(p_domn); + dest->zone = atoi(p_zone); + if( p_path[strlen(p_path)-1] == DIRSEPCHR ) + dest->path = xstrcpy(p_path); + else + dest->path = string_concat(p_path, DIRSEPSTR, NULL); + return(PROC_RC_OK); + } + else + { + log("zone isn't numeric value in domain specification"); + return(PROC_RC_IGNORE); + } + } + + log("incorrect domain specification"); + return(PROC_RC_IGNORE); +} + +/* + * Line format: [:] + */ +static int proc_modemport(s_modemport *dest, char *value) +{ + char *p_speed = NULL; + long speed = 0; + + ASSERT(dest != NULL && value != NULL); + + p_speed = strrchr(value, ':'); + + if( p_speed ) { + if( ISDEC(p_speed+1) ) + { + p_speed[0] = '\0'; + speed = atol(p_speed+1); + } + else + { + log("incorrect modem port \"%s\": bad lock speed", value); + return(PROC_RC_IGNORE); + } + } + + dest->name = xstrcpy(value); + dest->speed = speed; + + return(PROC_RC_OK); +} + +/* + * Line format:
+ */ +static int proc_password(s_falist *dest, char *value) +{ + s_faddr addr; + char *n = NULL; + char *p_addr = NULL; + char *p_passwd = NULL; + + ASSERT(dest != NULL && value != NULL); + + p_addr = string_token(value, &n, NULL, 1); + p_passwd = string_token(NULL, &n, NULL, 1); + + if( p_addr && *p_addr && p_passwd && *p_passwd ) + { + if( ftn_addrparse(&addr, p_addr, FALSE) == 0 ) + { + dest->addr = addr; + dest->what = xstrcpy(p_passwd); + return(PROC_RC_OK); + } + else + { + log("can't parse address \"%s\"", value); + return(PROC_RC_IGNORE); + } + } + + log("incorrect password specification"); + return(PROC_RC_IGNORE); +} + +/* + * Line format: + */ +static int proc_path(s_string *dest, char *value) +{ + ASSERT(dest != NULL && value != NULL); + + if( value[strlen(value)-1] == DIRSEPCHR ) + dest->str = xstrcpy(value); + else + dest->str = string_concat(value, DIRSEPSTR, NULL); + + return(PROC_RC_OK); +} + +/* + * Line format: < [String2[:RC]] ..> + */ +static int proc_dialresp(s_dialresp *dest, char *value) +{ + int i; + char *n = NULL; + char *p_mstr = NULL; + char *p_type = NULL; + char *p_retv = NULL; + + ASSERT(dest != NULL && value != NULL); + + p_mstr = string_token(value, &n, NULL, 1); + p_type = string_token(NULL, &n, NULL, 1); + p_retv = string_token(NULL, &n, NULL, 1); + + if( p_mstr && *p_mstr && p_type && *p_type ) + { + if( p_retv && !ISDEC(p_retv) ) + { + log("return code isn't numeric in modem response specification"); + return(PROC_RC_IGNORE); + } + + for( i = 0; resptypes[i].str; i++ ) + if( strcasecmp(p_type, resptypes[i].str) == 0 ) + break; + + if( resptypes[i].str ) + { + dest->mstr = xstrcpy(p_mstr); + dest->type = resptypes[i].value; + dest->retv = p_retv ? atoi(p_retv) : resptypes[i].retv; + return(PROC_RC_OK); + } + + log("unknown response type \"%s\"", p_type); + return(PROC_RC_IGNORE); + } + + log("incorrect modem response specification"); + return(PROC_RC_IGNORE); +} + +/* + * Line format: + */ +static int proc_translate(s_translate *dest, char *value) +{ + char *n = NULL; + char *p_find = NULL; + char *p_repl = NULL; + + ASSERT(dest != NULL && value != NULL); + + p_find = string_token(value, &n, NULL, 1); + p_repl = string_token(NULL, &n, NULL, 1); + + if( p_find && *p_find ) + { + dest->find = xstrcpy(p_find); + if( p_repl ) + dest->repl = xstrcpy(p_repl); + return(PROC_RC_OK); + } + + log("incorrect translation rule specification"); + return(PROC_RC_IGNORE); +} + +/* + * Line format: + */ +static int proc_speeddep(s_connlist *dest, char *value) +{ + char *n = NULL; + char *p_speed = NULL; + char *p_value = NULL; + + ASSERT(dest != NULL && value != NULL); + + p_speed = string_token(value, &n, NULL, 1); + p_value = string_token(NULL, &n, NULL, 1); + + if( p_speed && *p_speed && p_value && *p_value ) + { + if( ISDEC(p_speed) && ISDEC(p_value) ) + { + dest->speed = atoi(p_speed); + dest->value = atoi(p_value); + return(PROC_RC_OK); + } + log("non-numeric value \"%s\" or \"%s\"", p_speed, p_value); + return(PROC_RC_IGNORE); + } + + log("incorrect speed dependent config string"); + return(PROC_RC_IGNORE); +} + +/* + * Line format: [ ] + */ +static int proc_tries(s_tries *dest, char *value) +{ + int rc = PROC_RC_OK; + char *n = NULL; + char *p_tries = NULL; + char *p_action = NULL; + char *p_arg = NULL; + int action = TRIES_ACTION_UNDIALABLE; + int arg = 0; + + ASSERT(dest != NULL && value != NULL); + + p_tries = string_token(value, &n, NULL, 0); + p_action = string_token(NULL, &n, NULL, 0); + p_arg = string_token(NULL, &n, NULL, 0); + + if( p_tries && *p_tries && ISDEC(p_tries) ) + { + if( p_action && *p_action ) + { + if( strcasecmp(p_action, "undialable") == 0 ) + { + if( p_arg && *p_arg ) + { + log("no argument needed for action 'undialable'"); + rc = PROC_RC_WARN; + } + action = TRIES_ACTION_UNDIALABLE; + arg = 0; + } + else if( strcasecmp(p_action, "hold") == 0 ) + { + if( p_arg && *p_arg && !ISDEC(p_arg) ) + { + log("non-numeric argument for action 'hold'"); + return PROC_RC_IGNORE; + } + else if( p_arg == NULL ) + { + log("no argument for action 'hold'"); + return PROC_RC_IGNORE; + } + action = TRIES_ACTION_HOLDSYSTEM; + arg = atoi(p_arg); + } + else if( strcasecmp(p_action, "holdall") == 0 ) + { + if( p_arg && *p_arg && !ISDEC(p_arg) ) + { + log("non-numeric argument for action 'holdall'"); + return PROC_RC_IGNORE; + } + else if( p_arg == NULL ) + { + log("no argument for action 'holdall'"); + return PROC_RC_IGNORE; + } + action = TRIES_ACTION_HOLDALL; + arg = atoi(p_arg); + } + else + { + log("unknown action '%s'", p_action); + return PROC_RC_IGNORE; + } + } + dest->tries = atoi(p_tries); + dest->action = action; + dest->arg = arg; + return(rc); + } + + log("non-numeric tries number \"%s\"", p_tries); + return(PROC_RC_IGNORE); +} + +/* + * Line format: DebugLevel [].. + */ +#ifdef DEBUG +static int proc_debuglevel(s_number *dest, char *value) +{ + int rc = PROC_RC_OK; + long deblevel = 0L; + + ASSERT(dest != NULL && value != NULL); + + if( debug_parsestring(value, &deblevel) ) rc = PROC_RC_WARN; + + dest->num = deblevel; + + return(rc); +} +#endif + +/* + * Line format:
+ */ +static int proc_filebox(s_filebox *dest, char *value) +{ + s_faddr addr; + char *n = NULL; + char *p_path = NULL; + char *p_addr = NULL; + char *p_flav = NULL; + + ASSERT(dest != NULL && value != NULL); + + p_path = string_token(value, &n, NULL, 1); + p_addr = string_token(NULL, &n, NULL, 1); + p_flav = string_token(NULL, &n, NULL, 1); + + if( p_path && *p_path && p_addr && *p_addr ) + { + if( ftn_addrparse(&addr, p_addr, TRUE) == 0 ) + { + int flavor = FLAVOR_HOLD; + int rc = PROC_RC_OK; + + if( !is_directory(p_path) ) + { + log("filebox directory \"%s\" doesn't exist", p_path); + rc = PROC_RC_WARN; + } + if( p_flav && *p_flav ) + { + if( strcasecmp(p_flav, "hold") == 0 ) + flavor = FLAVOR_HOLD; + else if( strcasecmp(p_flav, "normal") == 0 ) + flavor = FLAVOR_NORMAL; + else if( strcasecmp(p_flav, "crash") == 0 ) + flavor = FLAVOR_CRASH; + else if( strcasecmp(p_flav, "immediate") == 0 ) + flavor = FLAVOR_IMMED; + else + { + log("unknown filebox flavor \"%s\"", p_flav); + rc = PROC_RC_WARN; + } + } + dest->addr = addr; + if( p_path[strlen(p_path)-1] == DIRSEPCHR ) + dest->path = xstrcpy(p_path); + else + dest->path = string_concat(p_path, DIRSEPSTR, NULL); + dest->flavor = flavor; + return rc; + } + else + { + log("can't parse address \"%s\"", p_addr); + return PROC_RC_IGNORE; + } + } + + log("incorrect filebox specification"); + return PROC_RC_IGNORE; +} diff --git a/source/bforce/conf_read.c b/source/bforce/conf_read.c new file mode 100644 index 0000000..2b4c349 --- /dev/null +++ b/source/bforce/conf_read.c @@ -0,0 +1,457 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +#define COMMENTCHR '#' +#define PREPROCCHR '$' +#define ESCAPECHR '\\' + +int conf_postreadcheck(void) +{ + return 0; +} + +const char *conf_getconfname(void) +{ + const char *name = getenv("BFCONFIG"); + if( name == NULL || *name == '\0' ) name = BFORCE_CFGFILE; + return(name); +} + +int conf_readpasswdlist(s_falist **pwdlist, char *fname) +{ + return(0); +} + +/* + * Prepare config string for parsing, check for comments + * Return: zero - good string, non-zero - .. (you know) + */ +static int conf_checkstr(char *str) +{ + int rc = 0; + char *p = NULL; + + ASSERT(str != NULL); + + if( isspace(*str) ) string_trimleft(str); + if( *str == '\0' || *str == COMMENTCHR ) + { rc = 1; } + + if( (p = strrchr(str, COMMENTCHR)) && *(p-1) != ESCAPECHR ) + { *p = '\0'; } + + string_trimright(str); + + return rc; +} + +/* + * Parse config string on: keyword, expression and value + * Return: zero - no errors, non-zero - incorrect syntax + */ +static void conf_parsestr(char *str, char **key, char **expr, char **value) +{ + char *k = NULL; /* Keyword */ + char *e = NULL; /* Expression */ + char *v = NULL; /* Value */ + char *p = NULL; + int brackets = 0; + + ASSERT(str != NULL && key != NULL && expr != NULL && value != NULL); + + *key = NULL; *expr = NULL; *value = NULL; + + /* Get config keyword */ + k = str; + while( isspace(*k) ) k++; + p = k; + while( !isspace(*p) && *p ) p++; + if( *p == '\0' ) + { *key = k; return; } + *p++ = '\0'; + + while( isspace(*p) ) p++; + v = p; + + /* Get config expression (if specified) */ + if( *p == '(' ) + { + ++p; + while( isspace(*p) ) p++; + for( e = p, brackets = 1; brackets > 0 && *p; ) + { + if( *(p-1) != ESCAPECHR ) + { + switch( *p ) { + case '(': + ++brackets; break; + case ')': + --brackets; break; + } + } + if( brackets > 0 ) ++p; + } + if( *p != ')' ) return; /* No closing bracket */ + /* Remove trailing spaces */ + v = p--; + while( p > e && isspace(*p) ) *p-- = '\0'; + *v++ = '\0'; + } + + /* Get config value */ + while( isspace(*v) ) v++; + if( *v == '\0' ) + { *key = k; *expr = e; return; } + /* Remove trailing spaces */ + p = v + strlen(v+1); + while( p > v && isspace(*p) ) *p-- = '\0'; + + /* Return information to function caller */ + *key = k; + *expr = e; + *value = v; + + return; +} + +int conf_readconf(const char *confname, int inclevel) +{ + FILE *fp = NULL; + char tmp[BF_MAXCFGLINE + 1]; + int rc, maxrc = 0; + int line = 0; + char *fullstr = NULL; /* Result of strings concatenation */ + char *value = NULL; + char *expr = NULL; + char *p_key = NULL; + char *p_expr = NULL; + char *p_value = NULL; + char *p = NULL; + char *ifexpr = NULL; /* Pointer to the `common' block expression */ + bool isappend = FALSE; /* Append new string to the previous? */ + bool isifexpr = FALSE; /* We are in `common' config block! */ + + if( inclevel == 0 ) + { + int i; + + /* Check config table correctness */ + for( i = 0; bforce_config[i].name; i++ ) + { + if( i != (int)bforce_config[i].real_key ) + { + log("invalid config table: found %d instead of %d", + bforce_config[i].real_key, i); + return -1; + } + } + } + + if( (fp = file_open(confname,"r")) == NULL ) + { + logerr("can't open config file \"%s\"", confname); + return(PROC_RC_IGNORE); + } + + DEB((D_CONFIG, "readconfig: start reading config \"%s\"", confname)); + + while( fgets(tmp, sizeof(tmp), fp) ) + { + ++line; + string_chomp(tmp); + + if( conf_checkstr(tmp) ) + { + if( isifexpr ) + { + log("warning: automatically close expression at empty line %d", line); + if( ifexpr ) { free(ifexpr); ifexpr = NULL; } + isifexpr = FALSE; + } + + if( !isappend ) + continue; + + log("warning: appending empty or comment line %d", line); + isappend = FALSE; + } + + p = tmp + strlen(tmp+1); + + if( *p == '\\' && *(p-1) != ESCAPECHR ) + { + *p = '\0'; + if( fullstr && isappend ) + { + fullstr = xstrcat(fullstr, tmp); + } + else + { + if( fullstr ) free(fullstr); + fullstr = xstrcpy(tmp); + isappend = TRUE; + } + continue; + } + else if( isappend ) + { + if( fullstr ) + { fullstr = xstrcat(fullstr, tmp); } + else + { ASSERT_MSG(); } + isappend = FALSE; + } + + /* + * Now we have string without comments + * and trailing/leading spaces in: + * - if single string than in $tmp[] + * - if concatanated strings than look $fullstr + */ + + p_key = NULL; + p_expr = NULL; + p_value = NULL; + + conf_parsestr(fullstr ? fullstr : tmp, &p_key, &p_expr, &p_value); + + DEB((D_CONFIG, "conf_readconf: [%d] key \"%s\" expr \"%s\" value \"%s\"", + line, p_key, p_expr, p_value)); + + if( p_value ) + { + value = xstrcpy(p_value); + string_dequote(value, p_value); + } + + if( p_expr ) + { + expr = xstrcpy(p_expr); + string_dequote(expr, p_expr); + } + + if( p_key && *p_key == PREPROCCHR ) + { + /* Preprocessor directives */ + + rc = PROC_RC_OK; + + if( strcasecmp(p_key+1, "include") == 0 ) + { + if( value == NULL || expr ) + { + log("incorrect usage of `%s' directive", p_key); + rc = PROC_RC_IGNORE; + } + else if( inclevel < MAXINCLUDELEVEL ) + { + DEB((D_CONFIG, "conf_readconf: process inlude file \"%s\"", value)); + rc = conf_readconf(value, inclevel + 1); + if( rc ) rc = PROC_RC_IGNORE; + } + else + { + DEB((D_CONFIG, "conf_readconf: too deep include")); + log("including level too deep"); + rc = PROC_RC_IGNORE; + } + } + else if( strcasecmp(p_key+1, "ifexp") == 0 ) + { + if( value || isifexpr ) + { + log("incorrect usage of `%s' directive", p_key); + rc = PROC_RC_ABORT; + } + else + { + if( ifexpr ) + { free(ifexpr); ifexpr = NULL; } + if( expr ) + ifexpr = xstrcpy(expr); + isifexpr = TRUE; + } + } + else if( strcasecmp(p_key+1, "endif") == 0 ) + { + if( value || expr || !isifexpr ) + { + log("incorrect usage of `%s' directive", p_key); + rc = PROC_RC_IGNORE; + } + else + { + if( ifexpr ) { free(ifexpr); ifexpr = NULL; } + isifexpr = FALSE; + } + } + else if( strcasecmp(p_key+1, "logfile") == 0 ) + { + if( value == NULL || expr ) + { + log("incorrect usage of `%s' directive", p_key); + rc = PROC_RC_IGNORE; + } + else + { + if( log_reopen(value, NULL, NULL) ) + { + log("can't continue without logging"); + rc = PROC_RC_ABORT; + } + } + } + else if( strcasecmp(p_key+1, "debugfile") == 0 ) + { + if( value == NULL || expr ) + { + log("incorrect usage of `%s' directive", p_key); + rc = PROC_RC_IGNORE; + } + else +#ifdef DEBUG + { + if( debug_isopened() ) debug_close(); + debug_setfilename(value); + } +#else + { + log("incorrect directive `%s': no debug code", p_key); + rc = PROC_RC_IGNORE; + } +#endif + } + else if( strcasecmp(p_key+1, "debuglevel") == 0 ) + { + if( value == NULL || expr ) + { + rc = PROC_RC_IGNORE; + } + else +#ifdef DEBUG + { + unsigned long newlevel = 0L; + + if( debug_parsestring(value, &newlevel) ) + { + rc = PROC_RC_WARN; + } + debug_setlevel(newlevel, 1); + } +#else + { + log("incorrect directive `%s': no debug code", p_key); + rc = PROC_RC_IGNORE; + } +#endif + } + else + { + log("unknown directive `%s'", p_key); + rc = PROC_RC_IGNORE; + } + } + else if( p_key && value ) + { + if( isifexpr && expr ) + { + log("can't use expressions inside $ifexpr block"); + rc = PROC_RC_IGNORE; + } + else if( isifexpr ) + { + rc = proc_configline(p_key, ifexpr, value); + } + else + { + rc = proc_configline(p_key, expr, value); + } + } + else + { + log("incorrect config string"); + rc = PROC_RC_IGNORE; + } + + if( fullstr ) + { free(fullstr); fullstr = NULL; } + if( value ) + { free(value); value = NULL; } + if( expr ) + { free(expr); expr = NULL; } + + switch(rc) { + case PROC_RC_OK: + break; + case PROC_RC_WARN: + log("warning in config \"%s\" line %d", confname, line); + break; + case PROC_RC_IGNORE: + log("ignore line %d in config \"%s\"", line, confname); + break; + case PROC_RC_ABORT: + log("fatal error in config \"%s\" in line %d", confname, line); + break; + default: + ASSERT_MSG(); + break; + } + if( rc == PROC_RC_ABORT ) { maxrc = 1; break; } + } /* end of while */ + + file_close(fp); + + if( isifexpr ) + { maxrc = 1; log("unterminated directive `#ifexp'"); } + + if( fullstr ) + free(fullstr); + if( ifexpr ) + free(ifexpr); + + DEB((D_CONFIG, "readconfig: exit with maxrc = %d", maxrc)); + + return maxrc; +} + +#ifdef DEBUG +void debug_override(void) +{ + s_cval_entry *ptrl; + char abuf[BF_MAXADDRSTR+1]; + + DEB((D_CONFIG, "debug_override: BEGIN")); + + for( ptrl = bforce_config[cf_override].data; ptrl; ptrl = ptrl->next ) + { + DEB((D_CONFIG, "log_overridelist: address %s", + ftn_addrstr(abuf, ptrl->d.override.addr))); + DEB((D_CONFIG, "log_overridelist: \tIpaddr = \"%s\"", + ptrl->d.override.sIpaddr)); + DEB((D_CONFIG, "log_overridelist: \tPhone = \"%s\"", + ptrl->d.override.sPhone)); + DEB((D_CONFIG, "log_overridelist: \tWorktime = \"%s\"", + timevec_string(abuf, &ptrl->d.override.worktime, sizeof(abuf)))); + DEB((D_CONFIG, "log_overridelist: \tFlags = \"%s\"", + ptrl->d.override.sFlags)); + } + + DEB((D_CONFIG, "debug_override: END")); +} +#endif /* DEBUG */ + diff --git a/source/bforce/daemon.c b/source/bforce/daemon.c new file mode 100644 index 0000000..bdd45d4 --- /dev/null +++ b/source/bforce/daemon.c @@ -0,0 +1,1041 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" +#include "io.h" +#include "session.h" +#include "outbound.h" +#include "daemon.h" + +/* + * Maxumum number of simultaneously running clients + */ +int max_tcpip = 0; +int max_modem = 0; + +/* + * Current number of running clients + */ +int tcpip_clients = 0; +int modem_clients = 0; + +/* + * Write queue/demon status to the log every XX seconds + */ +#define DAEMON_ALIVE_TIMER 1200 + +/* + * Time to sleep than all queues are in "DQ_Idle" state + */ +#define DAEMON_IDLE_SLEEP 5 + +/* + * Table of handled signals + */ +struct { + int signum; + DM_State state; + bool wait; +} daemon_signals[] = { + { SIGHUP, DM_Restart, FALSE }, + { SIGINT, DM_Shutdown, FALSE }, + { SIGTERM, DM_Shutdown, FALSE }, + { SIGUSR1, DM_Usr1, FALSE }, + { SIGUSR2, DM_Usr2, FALSE }, + { 0, 0, FALSE } +}; + +/* + * Systems queue (with all adresses, flavors, etc.) + */ +s_sysqueue daemon_sys_queue; + +/* + * Outgoing calls queues + */ +s_daemon_queue daemon_queues[] = { + { &daemon_sys_queue, -1, 0, FALSE, DQ_Idle }, /* Modem */ + { &daemon_sys_queue, -1, 0, TRUE, DQ_Idle }, /* IP */ + { NULL, -1, 0, FALSE, DQ_Idle } +}; + +/* + * Positions of the certain queues in the 'daemon_queues' array + */ +#define MODEM_QUEUE 0 +#define TCPIP_QUEUE 1 + +static RETSIGTYPE daemon_sighandler_chld(int sig) +{ + int old_errno = errno; + int rc, status; + pid_t pid; + + while( (pid = waitpid(-1, &status, WNOHANG)) > 0 ) + { + rc = WIFEXITED(status) ? WEXITSTATUS(status) : -1; + if( daemon_branch_exit(pid, rc) == -1 ) + log("wait got unexpected pid %d", (int)pid); + } + + signal(SIGCHLD, daemon_sighandler_chld); + errno = old_errno; +} + +static RETSIGTYPE daemon_sighandler(int signum) +{ + int i; + + for( i = 0; daemon_signals[i].signum; i++ ) + if( daemon_signals[i].signum == signum ) + { + daemon_signals[i].wait = TRUE; + return; + } + + log("daemon got unexpected signal %d", signum); +} + +static int daemon_sysentry_init(s_sysentry *sysent) +{ + s_override *p; + char msg[64] = ""; + char abuf[BF_MAXADDRSTR+1]; + + /* Read calls/sessions statistic from sts file */ + (void)session_stat_get(&sysent->stat, &sysent->node.addr); + + /* Lookup node in nodelist */ + (void)nodelist_lookup(&sysent->node, sysent->node.addr); + + /* Set overrides */ + if( (p = conf_override(cf_override, sysent->node.addr)) ) + { + sysent->overrides = p; + sysent->lineptr = NULL; + sysent->line = 0; + } + + if( sysent->node.keyword == KEYWORD_HOLD ) + { + strcpy(msg, "hold by nodelist"); + sysent->stat.undialable = TRUE; + } + else if( sysent->node.keyword == KEYWORD_DOWN ) + { + strcpy(msg, "down by nodelist"); + sysent->stat.undialable = TRUE; + } + else if( sysent->stat.undialable ) + strcpy(msg, "undialable"); + else if( sysent->stat.hold_until ) + { + int holdtime = sysent->stat.hold_until - time(0); + + if( holdtime > 0 ) + sprintf(msg, "calls holded for %d seconds", holdtime); + else + strcpy(msg, "calls holded"); + } + else if( sysent->stat.hold_freqs ) + { + int holdtime = sysent->stat.hold_freqs - time(0); + + if( holdtime > 0 ) + sprintf(msg, "freqs holded for %d seconds", holdtime); + else + strcpy(msg, "freqs holded"); + } + + if( msg && *msg ) + log("QUEUE: add %s (%s)", ftn_addrstr(abuf, sysent->node.addr), msg); + else + log("QUEUE: add %s", ftn_addrstr(abuf, sysent->node.addr)); + + return 0; +} + +static int daemon_sysentry_deinit(s_sysentry *sysent) +{ + char abuf[BF_MAXADDRSTR+1]; + + log("QUEUE: remove %s", ftn_addrstr(abuf, sysent->node.addr)); + + return 0; +} + +static bool daemon_node_cancall_line(const s_node *node, const s_override *ovrd) +{ + bool good_phone = FALSE; + bool good_host = FALSE; + bool good_time = FALSE; + time_t unixtime = time(NULL); + struct tm *now = localtime(&unixtime); + + /* + * Check phone number + */ + if( ovrd && ovrd->sPhone && *ovrd->sPhone ) + { + if( modem_isgood_phone(ovrd->sPhone) ) + good_phone = TRUE; + } + else if( node && node->phone && *node->phone ) + { + if( modem_isgood_phone(node->phone) ) + good_phone = TRUE; + } + + /* + * Check host name (IP address) + */ + if( ovrd && ovrd->sIpaddr && *ovrd->sIpaddr ) + { + if( tcpip_isgood_host(ovrd->sIpaddr) ) + good_host = TRUE; + } + + /* + * Check work time + */ + if( ovrd && timevec_isdefined(&ovrd->worktime) ) + { + if( timevec_isnow(&ovrd->worktime, now) ) + good_time = TRUE; + } + else if( ovrd && ovrd->sFlags && !nodelist_checkflag(ovrd->sFlags, "CM") ) + { + /* + * It is not an error. We check CM flag only + * if the work time was not specified in the override + */ + good_time = TRUE; + } + else if( node && timevec_isdefined(&node->worktime) ) + { + if( timevec_isnow(&node->worktime, now) ) + good_time = TRUE; + } + + if( good_time ) + { + if( good_host ) + return 2; + else if( good_phone ) + return 1; + } + + return 0; +} + +enum { UNHOLD_CALLS, UNHOLD_FREQS }; + +static void daemon_unhold_system(s_sysentry *syst, int mode) +{ + char abuf[BF_MAXADDRSTR+1]; + s_sess_stat stat_diff; + + memset(&stat_diff, '\0', sizeof(s_sess_stat)); + + /* + * Reset try counters to the TRIES_RESET value + */ + session_stat_reset_counters(&stat_diff); + + if( mode == UNHOLD_FREQS ) + stat_diff.hold_freqs = HOLD_RESET; + else + stat_diff.hold_until = HOLD_RESET; + + /* + * Write new statistic to the sts file + */ + if( session_stat_apply_diff(syst->node.addr, stat_diff) == -1 ) + { + log("cannot write statistic for address %s", + ftn_addrstr(abuf, syst->node.addr)); + } + + /* + * Read new statistic from sts file, ignore errors + */ + (void)session_stat_get(&syst->stat, &syst->node.addr); +} + +static bool daemon_node_cancall(s_sysentry *syst, bool ign_wtime, bool tcpip) +{ + char abuf[BF_MAXADDRSTR+1]; + const s_override *ptrl, *lastptr; + int line; + int rc; + + /* Is this system allready active in an another queue? Skip. */ + if( syst->busy ) + return FALSE; + + /* Check for undialable flag */ + if( syst->stat.undialable ) + return FALSE; + + if( daemon_branch_exist(syst->node.addr) ) + return FALSE; + + /* Check for netmail presence, when MAILONLY */ + if( conf_options(cf_options) & OPTIONS_MAILONLY ) + if ( !( syst->types & TYPE_NETMAIL ) ) + return FALSE; + + /* Check system hold status */ + if( syst->stat.hold_until > 0 ) + { + if( time(0) > syst->stat.hold_until ) + { + log("unholding %s", ftn_addrstr(abuf, syst->node.addr)); + daemon_unhold_system(syst, UNHOLD_CALLS); + } + else + return FALSE; + } + + /* Check freq hold status */ + if( syst->stat.hold_freqs > 0 ) + { + if( time(0) > syst->stat.hold_freqs ) + { + log("unholding freqs for %s", ftn_addrstr(abuf, syst->node.addr)); + daemon_unhold_system(syst, UNHOLD_FREQS); + } + else if( !syst->flavors && (syst->types & TYPE_REQUEST) ) + return FALSE; + } + + /* Make checks for all lines */ + if( syst->overrides ) + { + if( syst->lineptr && syst->lineptr->hidden ) + { + line = syst->line + 1; + /* Check lines after current */ + for( ptrl = syst->lineptr->hidden; ptrl; ptrl = ptrl->hidden ) + { + if( (rc = daemon_node_cancall_line(NULL, ptrl)) + && (rc == (tcpip ? 2 : 1)) ) + { + syst->line = line; + syst->lineptr = ptrl; + syst->tcpip = (rc == 2) ? TRUE : FALSE; + return TRUE; + } + line++; + } + } + + if( syst->lineptr == NULL ) + { lastptr = NULL; syst->line = 0; } + else + { lastptr = syst->lineptr->hidden; } + + line = 0; + /* Check lines before current */ + for( ptrl = syst->overrides; ptrl && ptrl != lastptr; ptrl = ptrl->hidden ) + { + if( (rc = daemon_node_cancall_line(line ? NULL : &syst->node, ptrl)) + && (rc == (tcpip ? 2 : 1)) ) + { + syst->line = line; + syst->lineptr = ptrl; + syst->tcpip = (rc == 2) ? TRUE : FALSE; + return TRUE; + } + line++; + } + } + else /* Node without overriden parameters */ + { + syst->line = line = 0; + return daemon_node_cancall_line(&syst->node, NULL); + } + + return FALSE; +} + +static int daemon_getnext(const s_sysqueue *q, int current, bool tcpip) +{ + int i; + int normal = -1; + + if( current < 0 ) + current = 0; + + /* Check systems AFTER the current */ + for( i = current + 1; i < q->sysnum; i++ ) + { + if( q->systab[i].flavors & FLAVOR_IMMED ) { + if( daemon_node_cancall(&q->systab[i], TRUE, tcpip) ) + return i; + } else if( q->systab[i].flavors & FLAVOR_CRASH ) { + if( daemon_node_cancall(&q->systab[i], FALSE, tcpip) ) + return i; + } else if( q->systab[i].flavors & FLAVOR_DIRECT + || q->systab[i].flavors & FLAVOR_NORMAL ) { + if( normal == -1 && daemon_node_cancall(&q->systab[i], FALSE, tcpip) ) + normal = i; + } + } + + /* Check systems BEFORE the current */ + for( i = 0; (i < current + 1) && (i < q->sysnum); i++ ) + { + if( q->systab[i].flavors & FLAVOR_IMMED ) { + if( daemon_node_cancall(&q->systab[i], TRUE, tcpip) ) + return i; + } else if( q->systab[i].flavors & FLAVOR_CRASH ) { + if( daemon_node_cancall(&q->systab[i], FALSE, tcpip) ) + return i; + } else if( q->systab[i].flavors & FLAVOR_DIRECT + || q->systab[i].flavors & FLAVOR_NORMAL ) { + if( normal == -1 && daemon_node_cancall(&q->systab[i], FALSE, tcpip) ) + normal = i; + } + } + + return normal; +} + +static int daemon_getnext2(const s_sysqueue *q, int current, bool tcpip) +{ + int next; + + /* Unlock previous system if available */ + if( current >= 0 ) + q->systab[current].busy = FALSE; + + next = daemon_getnext(q, current, tcpip); + + /* Lock new system */ + if( next >= 0 ) + q->systab[next].busy = TRUE; + + return next; +} + +static void daemon_do_tries_action(s_sysqueue *q, int pos, s_tries *act, const char *msg) +{ + s_sess_stat stat_diff; + char abuf[BF_MAXADDRSTR+1]; + + memset(&stat_diff, '\0', sizeof(s_sess_stat)); + + if( act->action == TRIES_ACTION_UNDIALABLE ) + { + log("set %s undialable: %s", + ftn_addrstr(abuf, q->systab[pos].node.addr), msg); + stat_diff.undialable = TRUE; + } + else if( act->action == TRIES_ACTION_HOLDSYSTEM ) + { + log("hold %s for %d seconds: %s", + ftn_addrstr(abuf, q->systab[pos].node.addr), act->arg, msg); + stat_diff.hold_until = time(NULL) + act->arg; + } + else if( act->action == TRIES_ACTION_HOLDALL ) + { + log("hold all systems for %d seconds: %s", act->arg, msg); + q->holduntil = time(NULL) + act->arg; + } + + /* + * Write new statistic to the sts file + */ + if( session_stat_apply_diff(q->systab[pos].node.addr, stat_diff) == -1 ) + { + log("cannot write statistic for address %s", + ftn_addrstr(abuf, q->systab[pos].node.addr)); + } + + /* + * Read new statistic from sts file, ignore errors + */ + (void)session_stat_get(&q->systab[pos].stat, + &q->systab[pos].node.addr); +} + +static void daemon_process_rc(s_sysqueue *q, s_faddr addr, int rc) +{ + int i; + s_tries *maxtries = NULL; + s_tries *maxtries_noansw = NULL; + s_tries *maxtries_noconn = NULL; + s_tries *maxtries_nodial = NULL; + s_tries *maxtries_hshake = NULL; + s_tries *maxtries_sessns = NULL; + char abuf[BF_MAXADDRSTR+1]; + + for( i = 0; i < q->sysnum; i++ ) + if( ftn_addrcomp(q->systab[i].node.addr, addr) == 0 ) + break; + + if( i < q->sysnum ) + { + /* Set last call finish time */ + q->systab[i].lastcall = time(0); + + /* Temporary set `state' structure to + make dynamical configuration work! */ + state.valid = TRUE; + state.node = q->systab[i].node; + state.listed = q->systab[i].node.listed; + + maxtries = conf_tries(cf_maxtries); + maxtries_noansw = conf_tries(cf_maxtries_noansw); + maxtries_noconn = conf_tries(cf_maxtries_noconn); + maxtries_nodial = conf_tries(cf_maxtries_nodial); + maxtries_hshake = conf_tries(cf_maxtries_hshake); + maxtries_sessns = conf_tries(cf_maxtries_sessions); + + /* Reset `state' structure */ + init_state(&state); + + /* Update statistic, ignore errors */ + session_stat_get(&q->systab[i].stat, &addr); + + log("%s: rc = %d [%d/%d/%d/%d/%d/%d]", + ftn_addrstr(abuf, addr), rc, + q->systab[i].stat.tries, + q->systab[i].stat.tries_noansw, + q->systab[i].stat.tries_noconn, + q->systab[i].stat.tries_nodial, + q->systab[i].stat.tries_hshake, + q->systab[i].stat.tries_sessns); + + DEB((D_DAEMON, "daemon_process_rc: address %s: [%d/%d/%d/%d/%d/%d]", + ftn_addrstr(abuf, addr), + q->systab[i].stat.tries, + q->systab[i].stat.tries_noansw, + q->systab[i].stat.tries_noconn, + q->systab[i].stat.tries_nodial, + q->systab[i].stat.tries_hshake, + q->systab[i].stat.tries_sessns)); + + if( maxtries && q->systab[i].stat.tries >= maxtries->tries ) + { + daemon_do_tries_action(q, i, maxtries, "reached maximal tries count"); + } + else if( maxtries_noansw && q->systab[i].stat.tries_noansw >= maxtries_noansw->tries ) + { + daemon_do_tries_action(q, i, maxtries_noansw, "reached maximal no answers count"); + } + else if( maxtries_noconn && q->systab[i].stat.tries_noconn >= maxtries_noconn->tries ) + { + daemon_do_tries_action(q, i, maxtries_noconn, "reached maximal connect failures count"); + } + else if( maxtries_nodial && q->systab[i].stat.tries_nodial >= maxtries_nodial->tries ) + { + daemon_do_tries_action(q, i, maxtries_nodial, "reached maximal no dialtone count"); + } + else if( maxtries_hshake && q->systab[i].stat.tries_hshake >= maxtries_hshake->tries ) + { + daemon_do_tries_action(q, i, maxtries_hshake, "reached maximal handshake failures count"); + } + else if( maxtries_sessns && q->systab[i].stat.tries_sessns >= maxtries_sessns->tries ) + { + daemon_do_tries_action(q, i, maxtries_sessns, "reached maximal session failures count"); + } + } + else + { + /* No entry in the systems queue + * TODO: load statistic and check tries? */ + log("%s: rc = %d", + ftn_addrstr(abuf, addr), rc); + DEB((D_DAEMON, "daemon_process_rc: address %s: [%d/%d/%d/%d/%d]", + ftn_addrstr(abuf, addr))); + } +} + +static void daemon_alive_message(s_sysqueue *q) +{ + int i, holded_num = 0; + + for( i = 0; i < q->sysnum; i++ ) + if( q->systab[i].stat.hold_until + || q->systab[i].stat.hold_freqs ) + holded_num++; + + log("still alive (%d systems, %d holded, %d branches)", + q->sysnum, holded_num, daemon_branch_number()); +} + +static void daemon_queue_do(s_daemon_queue *dq) +{ + bool select_next_address = FALSE; + s_sysqueue *q = dq->q; +#ifdef DEBUG + char abuf[BF_MAXADDRSTR+1]; +#endif + + if( dq->current >= 0 ) + { + if( (q->systab[dq->current].lastcall == 0) + || (q->systab[dq->current].lastcall + dq->circle < time(0)) ) + { + if( !daemon_branch_exist(q->systab[dq->current].node.addr) ) + { + DEB((D_DAEMON, "daemon_queue: calling %s", + ftn_addrstr(abuf, q->systab[dq->current].node.addr))); + if( !daemon_call(&q->systab[dq->current]) ) + select_next_address = TRUE; + } + else + select_next_address = TRUE; + } + } + else + select_next_address = TRUE; + + if( select_next_address ) + { + int next = daemon_getnext2(q, dq->current, dq->tcpip); + DEB((D_DAEMON, "daemon_queue: next = %d, current = %d", + next, dq->current)); + + if( next >= 0 ) + { + dq->current = next; + + /* + * Temporary set `state' structure to + * make dynamical configuration work! + */ + state.valid = TRUE; + state.node = q->systab[dq->current].node; + state.listed = q->systab[dq->current].node.listed; + state.inet = dq->tcpip; + + if( (q->systab[dq->current].flavors & FLAVOR_IMMED) ) + dq->circle = conf_number(cf_daemon_circle_immed); + else if( (q->systab[dq->current].flavors & FLAVOR_CRASH) ) + dq->circle = conf_number(cf_daemon_circle_crash); + else if( (q->systab[dq->current].flavors & FLAVOR_DIRECT) ) + dq->circle = conf_number(cf_daemon_circle_direct); + else + dq->circle = conf_number(cf_daemon_circle_normal); + + init_state(&state); + } + else + dq->current = -1; + } +} + +void daemon_queues_update_current(s_daemon_queue dqs[], int pos) +{ + int i; + + for( i = 0; dqs[i].q; i++ ) + { + if( dqs[i].current < 0 ) + continue; + + if( dqs[i].current == pos ) + dqs[i].current = -1; + else if( dqs[i].current > pos ) + dqs[i].current--; + } +} + +int daemon_rescan_sysqueue(s_sysqueue *q, s_daemon_queue dqs[]) +{ + int i; + s_outbound_callback_data ocb; + + out_reset_sysqueue(q); + + memset(&ocb, '\0', sizeof(s_outbound_callback_data)); + ocb.callback = out_handle_sysqueue; + ocb.dest = (void *)q; + if( out_scan(&ocb, NULL) ) + { + log("error scanning outbound"); + return -1; + } + + /* + * Remove empty entries from sysqueue (e.g. the mail was + * removed by the sysop or by an another program) + */ + for( i = 0; i < q->sysnum; i++ ) + if( !q->systab[i].types && !q->systab[i].flavors ) + { + out_remove_from_sysqueue(q, i); + daemon_queues_update_current(dqs, i); + } + +#ifdef DEBUG + log_sysqueue(q); +#endif + + return 0; +} + +int daemon_remove_waiting_branches(s_sysqueue *q, s_daemon_queue dqs[]) +{ + int i; + int j; + s_daemon_branch *bptr; +#ifdef DEBUG + char abuf[BF_MAXADDRSTR+1]; +#endif + + while( (i = daemon_branch_get_first_waiting()) >= 0 ) + { + bptr = daemon_branch_get_pointer(i); + if( !bptr ) + { + log("internal error: cannot get branch pointer!"); + return -1; + } + + DEB((D_DAEMON, "daemon: process branch information for %s, rc = %d", + ftn_addrstr(abuf, bptr->addr), bptr->rc)); + + if( bptr->tcpip ) + --tcpip_clients; + else + --modem_clients; + + daemon_process_rc(q, bptr->addr, bptr->rc); + + if( bptr->rc == BFERR_NOERROR ) + { + /* Remove system from queue */ + for( j = 0; j < q->sysnum; j++ ) + if( !ftn_addrcomp(bptr->addr, q->systab[j].node.addr) ) + { + out_remove_from_sysqueue(q, j); + daemon_queues_update_current(dqs, j); + } + } + + /* Hold modem line for some time */ + if( !bptr->tcpip && bptr->portname ) + { + daemon_line_hold(bptr->portname, + conf_number(cf_daemon_circle_modem)); + } + + /* Remove branch entry */ + daemon_branch_remove(i); + } + + return 0; +} + +#define PIDFILE_CREATE 1 +#define PIDFILE_DELETE 2 +#define PIDFILE_TERMINATE 3 + +int daemon_pidfile(int cmd) +{ + char *pidfile = conf_string(cf_daemon_pid_file); + pid_t hispid, mypid = getpid(); + FILE *pf; + struct stat sb; + + if( !pidfile ) + return 0; + + switch (cmd) { + case PIDFILE_CREATE: + if( !stat(pidfile, &sb) ) { + pf = fopen(pidfile, "r"); + if ( !pf ) { + log("daemon_pidfile: cannot open %s for reading", pidfile); + return -1; + } + + fscanf(pf, "%d", &hispid); + fclose(pf); + + if( hispid ) { + if( hispid == mypid ) + return 0; + if( !kill(hispid, 0) ) { + log("daemon_pidfile: another daemon exist. pid=%d", hispid); + return -1; + } + if( errno != ESRCH ) { + log("daemon_pidfile: error sending signal. pid=%d, errno=%d", hispid, errno); + return -1; + } + } + } else if( errno != ENOENT ) + { + log("daemon_pidfile: error stat(%s). errno=%d", pidfile, errno); + return -1; + } + + pf = fopen(pidfile, "w"); + if( !pf ) { + log("daemon_pidfile: cannot open %s for writing", pidfile); + return -1; + } + + fprintf(pf, "%d", mypid); + fclose(pf); + break; + + case PIDFILE_DELETE: + if( !stat(pidfile, &sb) ) { + pf = fopen(pidfile, "r"); + if( !pf ) { + log("daemon_pidfile: cannot open %s for reading", pidfile); + return -1; + } + + fscanf(pf, "%d", &hispid); + fclose(pf); + + if( !hispid || (hispid == mypid) ) { + unlink(pidfile); + return 0; + } else { + log("daemon_pidfile: oops! mypid=%d, hispid=%d", mypid, hispid); + return -1; + } + } else { + log("daemon_pidfile: error stat(%s). errno=%d", pidfile, errno); + return -1; + } + break; + + case PIDFILE_TERMINATE: + if( !stat(pidfile, &sb) ) { + pf = fopen(pidfile, "r"); + if( !pf ) { + log("daemon_pidfile: cannot open %s for reading", pidfile); + return -1; + } + + fscanf(pf, "%d", &hispid); + fclose(pf); + unlink(pidfile); + + if( hispid ) + kill(hispid, 15); + + } else { + log("daemon_pidfile: error stat(%s). errno=%d", pidfile, errno); + return -1; + } + break; + + default: + log("daemon_pidfile: undefined cmd = %d", cmd); + return -1; + } + + return 0; +} + +int daemon_run(const char *confname, const char *incname, bool quit) +{ + DM_State dmstate = DM_Start; + time_t timer_rescan = 0; + time_t timer_alive = 0; + bool started = FALSE; + int circle_rescan = 0; + int rc = 0; + int i; + + if ( quit ) { + daemon_pidfile(PIDFILE_TERMINATE); + exit(0); + } + + /* Initialisation */ + memset(&daemon_sys_queue, '\0', sizeof(s_sysqueue)); + + /* Install signal handlers */ + signal(SIGCHLD, daemon_sighandler_chld); + signal(SIGINT, daemon_sighandler); + signal(SIGTERM, daemon_sighandler); + signal(SIGHUP, daemon_sighandler); + signal(SIGUSR1, daemon_sighandler); + signal(SIGUSR2, daemon_sighandler); + + while(1) + { + switch(dmstate) { + case DM_Start: + DEB((D_DAEMON, "daemon: entering state DM_Start")); + + if ( daemon_pidfile(PIDFILE_CREATE) == -1 ) + exit(0); + + circle_rescan = conf_number(cf_daemon_circle_rescan); + max_tcpip = conf_number(cf_daemon_maxclients_tcpip); + max_modem = conf_number(cf_daemon_maxclients_modem); + + /* Set default values */ + if( !circle_rescan ) circle_rescan = 60; + + /* Disable counting of files/mail size */ + sysqueue_dont_count_sizes = TRUE; + + /* Setup sysqueue scanner callbacks */ + sysqueue_add_callback = daemon_sysentry_init; + sysqueue_rem_callback = daemon_sysentry_deinit; + + /* Reopen log and debug files */ + if( log_isopened() ) + log_close(); +#ifdef DEBUG + if( debug_isopened() ) + debug_close(); +#endif + if( log_open(log_getfilename(LOG_FILE_DAEMON), NULL, NULL) ) + { + log("can't continue without logging"); + return BFERR_FATALERROR; + } + +#ifdef DEBUG + (void)debug_setfilename(log_getfilename(LOG_FILE_DEBUG)); +#endif + + log("%sstarting daemon (%s)", + started ? "re" : "", BF_VERSION); + + started = TRUE; + dmstate = DM_ProcessQueues; + break; + + case DM_Restart: + DEB((D_DAEMON, "daemon: entering state DM_Restart")); + + /* Release memory */ + deinit_sysqueue(&daemon_sys_queue); + deinit_conf(); + + /* Reset queues */ + daemon_queues[MODEM_QUEUE].current = + daemon_queues[TCPIP_QUEUE].current = -1; + daemon_queues[MODEM_QUEUE].circle = + daemon_queues[TCPIP_QUEUE].circle = 0; + daemon_queues[MODEM_QUEUE].state = + daemon_queues[TCPIP_QUEUE].state = DQ_Idle; + + /* Read primary config file */ + if( confname && *confname ) + rc = conf_readconf(confname, 0); + else + rc = conf_readconf(conf_getconfname(), 0); + + if( rc ) + return(BFERR_FATALERROR); + + /* Read additional config file (manual include) */ + if( incname && *incname && conf_readconf(incname, 1) ) + log("cannot read additional config (ignore)"); + + dmstate = DM_Start; + break; + + case DM_ProcessQueues: + DEB((D_DAEMON, "daemon: entering state DM_ProcessQueues")); + + /* + * Handle received signals + */ + for( i = 0; daemon_signals[i].signum; i++ ) + if( daemon_signals[i].wait ) + break; + + if( daemon_signals[i].signum ) + { + daemon_signals[i].wait = FALSE; + dmstate = daemon_signals[i].state; + break; + } + + /* + * Process finished branches + */ + (void)daemon_remove_waiting_branches(&daemon_sys_queue, + daemon_queues); + + /* + * Check rescan timer + */ + if( !timer_running(timer_rescan) || timer_expired(timer_rescan) ) + { + (void)daemon_rescan_sysqueue(&daemon_sys_queue, + daemon_queues); + timer_set(&timer_rescan, circle_rescan); + } + + /* + * Check alive timer + */ + if( !timer_running(timer_alive) || timer_expired(timer_alive) ) + { + daemon_alive_message(&daemon_sys_queue); + timer_set(&timer_alive, DAEMON_ALIVE_TIMER); + } + + if( max_modem > 0 ) + daemon_queue_do(&daemon_queues[MODEM_QUEUE]); + if( max_tcpip > 0 ) + daemon_queue_do(&daemon_queues[TCPIP_QUEUE]); + + (void)sleep(DAEMON_IDLE_SLEEP); + break; + + case DM_Usr1: + DEB((D_DAEMON, "daemon: entering state DM_Usr1")); + + log("signal USR1 has no effect now. Have any ideas?"); + dmstate = DM_ProcessQueues; + + break; + + case DM_Usr2: + DEB((D_DAEMON, "daemon: entering state DM_Usr2")); + + log("signal USR2 has no effect now. Have any ideas?"); + dmstate = DM_ProcessQueues; + + break; + + case DM_Shutdown: + DEB((D_DAEMON, "daemon: entering state DM_Shutdown")); + + log("stopping daemon"); + daemon_pidfile(PIDFILE_DELETE); + + /* Release memory */ + deinit_sysqueue(&daemon_sys_queue); + daemon_branch_deinit(); + daemon_lines_deinit(); + deinit_conf(); + + exit(0); + } + } +} + diff --git a/source/bforce/daemon_branch.c b/source/bforce/daemon_branch.c new file mode 100644 index 0000000..1e6552e --- /dev/null +++ b/source/bforce/daemon_branch.c @@ -0,0 +1,161 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "daemon.h" + +static s_daemon_branch *daemon_branch_tab = NULL; +static signed int daemon_branch_num = 0; + + +#define ASSERT_POS(pos) ASSERT((pos) >= 0 && ((pos) + 1) <= daemon_branch_num \ + && daemon_branch_tab) + +bool daemon_branch_exist(s_faddr addr) +{ + int i; + + for( i = 0; i < daemon_branch_num; i++ ) + if( !ftn_addrcomp(daemon_branch_tab[i].addr, addr) ) + return TRUE; + + return FALSE; +} + +void daemon_branch_check_stop_timers(void) +{ + int i; + time_t now = time(0); + + for( i = 0; i < daemon_branch_num; i++ ) + if( daemon_branch_tab[i].stop && !daemon_branch_tab[i].wait + && now >= daemon_branch_tab[i].stop ) + { + if( kill(daemon_branch_tab[i].pid, SIGKILL) == -1 ) + logerr("cannot kill branch with PID %d", + (int)daemon_branch_tab[i].pid); + } +} + +int daemon_branch_exit(pid_t pid, int rc) +{ + int i; + + for( i = 0; i < daemon_branch_num; i++ ) + if( daemon_branch_tab[i].pid == pid ) + { + daemon_branch_tab[i].rc = rc; + daemon_branch_tab[i].wait = TRUE; + return 0; + } + + return -1; + +} + +int daemon_branch_get_first_waiting(void) +{ + int i; + + for( i = 0; i < daemon_branch_num; i++ ) + if( daemon_branch_tab[i].wait ) + return i; + + return -1; +} + +s_daemon_branch *daemon_branch_get_pointer(int pos) +{ + ASSERT_POS(pos); + + if( pos + 1 > daemon_branch_num ) + { + log("internal error: branch position is out of range"); + return NULL; + } + + return &daemon_branch_tab[pos]; +} + +void daemon_branch_add(s_faddr addr, pid_t pid, bool tcpip, const char *pname) +{ + if( daemon_branch_tab ) + { + daemon_branch_tab = + (s_daemon_branch *)xrealloc(daemon_branch_tab, + sizeof(s_daemon_branch)*(daemon_branch_num + 1)); + memset(&daemon_branch_tab[daemon_branch_num], '\0', + sizeof(s_daemon_branch)); + } + else + { + daemon_branch_tab = + (s_daemon_branch *)xmalloc(sizeof(s_daemon_branch)); + memset(daemon_branch_tab, '\0', sizeof(s_daemon_branch)); + daemon_branch_num = 0; + } + + daemon_branch_tab[daemon_branch_num].addr = addr; + daemon_branch_tab[daemon_branch_num].wait = FALSE; + daemon_branch_tab[daemon_branch_num].tcpip = tcpip; + daemon_branch_tab[daemon_branch_num].pid = pid; + daemon_branch_tab[daemon_branch_num].start = time(NULL); + + if( pname ) + daemon_branch_tab[daemon_branch_num].portname = xstrcpy(pname); + + daemon_branch_num++; +} + +void daemon_branch_remove(int pos) +{ + ASSERT_POS(pos); + + if( daemon_branch_tab[pos].portname ) + free(daemon_branch_tab[pos].portname); + + if( daemon_branch_num > 1 ) + { + memmove(&daemon_branch_tab[pos], + &daemon_branch_tab[pos+1], + sizeof(s_daemon_branch)*(daemon_branch_num - pos - 1)); + daemon_branch_tab = + (s_daemon_branch *)xrealloc(daemon_branch_tab, + sizeof(s_daemon_branch)*(daemon_branch_num - 1)); + daemon_branch_num--; + } + else + { + free(daemon_branch_tab); + daemon_branch_tab = NULL; + daemon_branch_num = 0; + } +} + +int daemon_branch_number(void) +{ + return daemon_branch_num; +} + +void daemon_branch_deinit(void) +{ + if( daemon_branch_tab ) + free(daemon_branch_tab); + + daemon_branch_tab = NULL; + daemon_branch_num = 0; +} + diff --git a/source/bforce/daemon_call.c b/source/bforce/daemon_call.c new file mode 100644 index 0000000..4aeac40 --- /dev/null +++ b/source/bforce/daemon_call.c @@ -0,0 +1,202 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" +#include "io.h" +#include "session.h" +#include "outbound.h" +#include "daemon.h" + +static s_modemport *daemon_getfree_port(const char *lockdir) +{ + s_cval_entry *ptrl; + + /* Find first not locked modem device */ + for( ptrl = conf_first(cf_modem_port); ptrl; ptrl = conf_next(ptrl) ) + { + if( port_checklock(lockdir, &ptrl->d.modemport) == LOCKCHECK_NOLOCK + && modem_candialout(ptrl->d.modemport.name) == TRUE + && daemon_line_isready(ptrl->d.modemport.name) ) + return &ptrl->d.modemport; + } + + return NULL; +} + +static int daemon_call_branch(s_sysentry *syst, const char *lockdir, s_modemport *port) +{ + int rc = BFERR_NOERROR; + char abuf[BF_MAXADDRSTR+1]; + + /* + * First of all restore the default signal handlers + */ + signal(SIGCHLD, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); + signal(SIGUSR1, SIG_DFL); + signal(SIGUSR2, SIG_DFL); + + /* + * Initialise ``state'' information structure + */ + init_state(&state); + state.caller = TRUE; + state.valid = TRUE; + state.node = syst->node; + state.listed = syst->node.listed; + state.modemport = (!syst->tcpip) ? port : NULL; + if( syst->lineptr ) + state.override = *syst->lineptr; + if( *state.node.addr.domain ) + *state.node.addr.domain = '\0'; + + /* + * Apply overrides to the node information + */ + if( state.override.sFlags ) + { + strnxcat(state.node.flags, ",", sizeof(state.node.flags)); + strnxcat(state.node.flags, state.override.sFlags, sizeof(state.node.flags)); + } + + if( !syst->tcpip && state.override.sPhone ) + (void)strnxcpy(state.node.phone, state.override.sPhone, sizeof(state.node.phone)); + else if( syst->tcpip && state.override.sIpaddr ) + (void)strnxcpy(state.node.phone, state.override.sIpaddr, sizeof(state.node.phone)); + + /* + * Try to lock address of system we are going to call + */ +#ifdef BFORCE_USE_CSY + if( out_bsy_lock(state.node.addr, TRUE) ) +#else + if( out_bsy_lock(state.node.addr) ) +#endif + gotoexit(BFERR_SYSTEM_LOCKED); + + setproctitle("bforce calling %s, %s", + ftn_addrstr(abuf, state.node.addr), state.node.phone); + + if( syst->tcpip ) + { + rc = call_system_tcpip(); + } + else /* via Modem */ + { + state.modemport = port; + if( port_lock(lockdir, state.modemport) ) + { + log("cannot lock modem port"); + rc = BFERR_PORTBUSY; + } + else /* Locked port */ + { + rc = call_system_modem(); + port_unlock(lockdir, state.modemport); + } + } + +exit: + out_bsy_unlockall(); + + log("session rc = %d (\"%s\")", rc, BFERR_NAME(rc)); + + (void)session_stat_update(&state.node.addr, + &state.sess_stat, TRUE, rc); + + deinit_state(&state); + + return rc; +} + +int daemon_call(s_sysentry *syst) +{ + pid_t chld_pid; + const char *p_lockdir = NULL; + char abuf[BF_MAXADDRSTR+1]; + s_modemport *modemport = NULL; + + /* + * Check number of allowed clients + */ + if( (syst->tcpip == TRUE && max_tcpip && max_tcpip <= tcpip_clients) + || (syst->tcpip == FALSE && max_modem && max_modem <= modem_clients) ) + { + DEB((D_DAEMON, "daemon_call: too many clients!")); + return 1; + } + + /* + * Check whether this node is allready locked + */ + if( out_bsy_check(syst->node.addr) ) + return 0; + + /* + * Set state structure to make expressions works properly now + */ + state.caller = TRUE; + state.valid = TRUE; + state.node = syst->node; + state.listed = syst->node.listed; + state.inet = syst->tcpip; + + if( syst->tcpip == FALSE ) + { + if( (p_lockdir = conf_string(cf_uucp_lock_directory)) == NULL ) + p_lockdir = BFORCE_LOCK_DIR; + + if( (modemport = daemon_getfree_port(p_lockdir)) == NULL ) + { + init_state(&state); + return 1; + } + } + + log("call %s line %d via %s", + ftn_addrstr(abuf, syst->node.addr), syst->line, + syst->tcpip ? "TCP/IP" : modemport->name); + + chld_pid = fork(); + + if( chld_pid > 0 ) + { + (void)daemon_branch_add(syst->node.addr, chld_pid, syst->tcpip, + syst->tcpip ? NULL : modemport->name); + + init_state(&state); + + if( syst->tcpip ) + ++tcpip_clients; + else + ++modem_clients; + + return 0; + } + else if( chld_pid < 0 ) + { + logerr("failed fork() call"); + return 1; + } + + /* Now we are in child process */ + + exit(daemon_call_branch(syst, p_lockdir, modemport)); +} + diff --git a/source/bforce/daemon_lines.c b/source/bforce/daemon_lines.c new file mode 100644 index 0000000..470448a --- /dev/null +++ b/source/bforce/daemon_lines.c @@ -0,0 +1,106 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +enum { LINE_TYPE_MODEM, LINE_TYPE_TCPIP }; + +typedef struct { + char *name; + time_t holdtimer; + int type; +} s_line; + +static s_line *lines_tab = NULL; +static int lines_num = 0; + +int daemon_line_add(const char *name, int type) +{ + int i; + + for( i = 0; i < lines_num; i++ ) + if( !strcmp(lines_tab[i].name, name) ) + return i; + + log("register new line \"%s\"", name); + + if( lines_tab ) + { + lines_tab = (s_line *)xrealloc(lines_tab, sizeof(s_line)*(lines_num+1)); + memset(&lines_tab[lines_num], '\0', sizeof(s_line)); + } + else + { + lines_tab = (s_line *)xmalloc(sizeof(s_line)); + memset(lines_tab, '\0', sizeof(s_line)); + } + + lines_tab[lines_num].name = xstrcpy(name); + lines_tab[lines_num].type = type; + + return lines_num++; +} + +void daemon_line_hold(const char *name, int holdtime) +{ + int i; + + for( i = 0; i < lines_num; i++ ) + if( !strcmp(lines_tab[i].name, name) ) + { + timer_set(&lines_tab[i].holdtimer, holdtime); + return; + } + + i = daemon_line_add(name, 0); + timer_set(&lines_tab[i].holdtimer, holdtime); +} + +bool daemon_line_isready(const char *name) +{ + int i; + + for( i = 0; i < lines_num; i++ ) + if( !strcmp(lines_tab[i].name, name) ) + { + if( !timer_running(lines_tab[i].holdtimer) + || timer_expired(lines_tab[i].holdtimer) ) + return TRUE; + + return FALSE; + } + + (void)daemon_line_add(name, 0); + return TRUE; +} + +void daemon_lines_deinit(void) +{ + int i; + + for( i = 0; i < lines_num; i++ ) + if( lines_tab[i].name ) + free(lines_tab[i].name); + + if( lines_tab ) + { + free(lines_tab); + lines_tab = NULL; + } + + lines_num = 0; +} + diff --git a/source/bforce/expression.tab.c b/source/bforce/expression.tab.c new file mode 100644 index 0000000..edf553f --- /dev/null +++ b/source/bforce/expression.tab.c @@ -0,0 +1,1733 @@ +/* A Bison parser, made by GNU Bison 1.875. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Written by Richard Stallman by simplifying the original so called + ``semantic'' parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + COMMA = 258, + TEXT = 259, + NUMBER = 260, + INCOMING = 261, + OUTGOING = 262, + LISTED = 263, + PROTECTED = 264, + CONNSPEED = 265, + EXEC = 266, + EXIST = 267, + PORT = 268, + MAILER = 269, + TZ = 270, + FLAG = 271, + SPEED = 272, + PHONE = 273, + TIME = 274, + ADDRESS = 275, + EQ = 276, + NE = 277, + GT = 278, + GE = 279, + LT = 280, + LE = 281, + AND = 282, + OR = 283, + NOT = 284, + XOR = 285, + OPENB = 286, + CLOSEB = 287, + AROP = 288, + LOGOP = 289 + }; +#endif +#define COMMA 258 +#define TEXT 259 +#define NUMBER 260 +#define INCOMING 261 +#define OUTGOING 262 +#define LISTED 263 +#define PROTECTED 264 +#define CONNSPEED 265 +#define EXEC 266 +#define EXIST 267 +#define PORT 268 +#define MAILER 269 +#define TZ 270 +#define FLAG 271 +#define SPEED 272 +#define PHONE 273 +#define TIME 274 +#define ADDRESS 275 +#define EQ 276 +#define NE 277 +#define GT 278 +#define GE 279 +#define LT 280 +#define LE 281 +#define AND 282 +#define OR 283 +#define NOT 284 +#define XOR 285 +#define OPENB 286 +#define CLOSEB 287 +#define AROP 288 +#define LOGOP 289 + + + + +/* Copy the first part of user declarations. */ +#line 48 "expression.y" + +#include "includes.h" +#include "confread.h" +#include "util.h" +#include "logger.h" +#include "session.h" +#include "nodelist.h" +#include "io.h" + +static struct tm *now = NULL; +static int expr_result = 0; +static char *expr_p_pos = NULL; +static char *expr_p_text = NULL; + +/* + * These are expression element checkers (not only) + * Return values: + * 0 - FALSE + * 1 - TRUE + * -1 - cannot check, because some data is not available yet + * -2 - invalid element (we should not check this expression more) + */ +static int expr_check_incoming(void); +static int expr_check_outgoing(void); +static int expr_check_protected(void); +static int expr_check_listed(void); +static int expr_check_logic(int e1, int op, int e2); +static int expr_check_phone(const char *phone); +static int expr_check_arop(int num1, int op, int num2); +static int expr_check_flag(const char *str); +static int expr_check_exec(const char *str); +static int expr_check_exist(const char *str); +static int expr_check_port(const char *str); +static int expr_check_mailer(const char *str); +static int expr_check_addr(const char *str); +static int expr_check_time(const char *str); + +static int yylex(void); +static int yyparse(void); +static int yyerror(const char *s); + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +typedef int YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 214 of yacc.c. */ +#line 197 "expression.tab.c" + +#if ! defined (yyoverflow) || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# if YYSTACK_USE_ALLOCA +# define YYSTACK_ALLOC alloca +# else +# ifndef YYSTACK_USE_ALLOCA +# if defined (alloca) || defined (_ALLOCA_H) +# define YYSTACK_ALLOC alloca +# else +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# else +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +# define YYSTACK_ALLOC malloc +# define YYSTACK_FREE free +# endif +#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */ + + +#if (! defined (yyoverflow) \ + && (! defined (__cplusplus) \ + || (YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + short yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (short) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + register YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (0) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined (__STDC__) || defined (__cplusplus) + typedef signed char yysigned_char; +#else + typedef short yysigned_char; +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 35 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 43 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 35 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 6 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 25 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 46 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 289 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const unsigned char yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const unsigned char yyprhs[] = +{ + 0, 0, 3, 5, 7, 10, 14, 18, 20, 22, + 24, 26, 29, 33, 37, 41, 44, 47, 50, 53, + 56, 59, 61, 63, 67, 69 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yysigned_char yyrhs[] = +{ + 36, 0, -1, 37, -1, 38, -1, 29, 37, -1, + 37, 34, 37, -1, 31, 37, 32, -1, 6, -1, + 7, -1, 8, -1, 9, -1, 16, 39, -1, 10, + 33, 5, -1, 17, 33, 5, -1, 15, 33, 5, + -1, 18, 4, -1, 19, 40, -1, 11, 4, -1, + 12, 4, -1, 13, 4, -1, 14, 4, -1, 4, + -1, 4, -1, 4, 3, 39, -1, 4, -1, 4, + 3, 40, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const unsigned char yyrline[] = +{ + 0, 92, 92, 98, 103, 111, 115, 121, 125, 129, + 133, 137, 141, 148, 155, 159, 163, 167, 171, 175, + 179, 183, 190, 194, 199, 205 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE +/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "COMMA", "TEXT", "NUMBER", "INCOMING", + "OUTGOING", "LISTED", "PROTECTED", "CONNSPEED", "EXEC", "EXIST", "PORT", + "MAILER", "TZ", "FLAG", "SPEED", "PHONE", "TIME", "ADDRESS", "EQ", "NE", + "GT", "GE", "LT", "LE", "AND", "OR", "NOT", "XOR", "OPENB", "CLOSEB", + "AROP", "LOGOP", "$accept", "fullline", "expression", "elemexp", + "flagstring", "timestring", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const unsigned short yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const unsigned char yyr1[] = +{ + 0, 35, 36, 37, 37, 37, 37, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 39, 39, 40, 40 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const unsigned char yyr2[] = +{ + 0, 2, 1, 1, 2, 3, 3, 1, 1, 1, + 1, 2, 3, 3, 3, 2, 2, 2, 2, 2, + 2, 1, 1, 3, 1, 3 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const unsigned char yydefact[] = +{ + 0, 21, 7, 8, 9, 10, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 3, 0, 17, 18, 19, 20, 0, 22, 11, 0, + 15, 24, 16, 4, 0, 1, 0, 12, 14, 0, + 13, 0, 6, 5, 23, 25 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yysigned_char yydefgoto[] = +{ + -1, 18, 19, 20, 28, 32 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -33 +static const yysigned_char yypact[] = +{ + -4, -33, -33, -33, -33, -33, -32, 15, 17, 18, + 19, -9, 22, -5, 25, 26, -4, -4, 31, -2, + -33, 28, -33, -33, -33, -33, 29, 32, -33, 33, + -33, 34, -33, -2, -14, -33, -4, -33, -33, 22, + -33, 26, -33, -2, -33, -33 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yysigned_char yypgoto[] = +{ + -33, -33, 0, -33, 1, 2 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const unsigned char yytable[] = +{ + 1, 21, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 33, 34, 42, 22, + 36, 23, 24, 25, 26, 16, 27, 17, 29, 30, + 31, 35, 36, 37, 38, 39, 43, 41, 40, 0, + 44, 0, 0, 45 +}; + +static const yysigned_char yycheck[] = +{ + 4, 33, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 16, 17, 32, 4, + 34, 4, 4, 4, 33, 29, 4, 31, 33, 4, + 4, 0, 34, 5, 5, 3, 36, 3, 5, -1, + 39, -1, -1, 41 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const unsigned char yystos[] = +{ + 0, 4, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 29, 31, 36, 37, + 38, 33, 4, 4, 4, 4, 33, 4, 39, 33, + 4, 4, 40, 37, 37, 0, 34, 5, 5, 3, + 5, 3, 32, 37, 39, 40 +}; + +#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) +# define YYSIZE_T __SIZE_TYPE__ +#endif +#if ! defined (YYSIZE_T) && defined (size_t) +# define YYSIZE_T size_t +#endif +#if ! defined (YYSIZE_T) +# if defined (__STDC__) || defined (__cplusplus) +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# endif +#endif +#if ! defined (YYSIZE_T) +# define YYSIZE_T unsigned int +#endif + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrlab1 + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror ("syntax error: cannot back up");\ + YYERROR; \ + } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +/* YYLLOC_DEFAULT -- Compute the default location (before the actions + are run). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + Current.first_line = Rhs[1].first_line; \ + Current.first_column = Rhs[1].first_column; \ + Current.last_line = Rhs[N].last_line; \ + Current.last_column = Rhs[N].last_column; +#endif + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +# define YYDSYMPRINT(Args) \ +do { \ + if (yydebug) \ + yysymprint Args; \ +} while (0) + +# define YYDSYMPRINTF(Title, Token, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yysymprint (stderr, \ + Token, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (cinluded). | +`------------------------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_stack_print (short *bottom, short *top) +#else +static void +yy_stack_print (bottom, top) + short *bottom; + short *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (/* Nothing. */; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yy_reduce_print (int yyrule) +#else +static void +yy_reduce_print (yyrule) + int yyrule; +#endif +{ + int yyi; + unsigned int yylineno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ", + yyrule - 1, yylineno); + /* Print the symbols being reduced, and their result. */ + for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++) + YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]); + YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]); +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YYDSYMPRINT(Args) +# define YYDSYMPRINTF(Title, Token, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#if YYMAXDEPTH == 0 +# undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined (__GLIBC__) && defined (_STRING_H) +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +# if defined (__STDC__) || defined (__cplusplus) +yystrlen (const char *yystr) +# else +yystrlen (yystr) + const char *yystr; +# endif +{ + register const char *yys = yystr; + + while (*yys++ != '\0') + continue; + + return yys - yystr - 1; +} +# endif +# endif + +# ifndef yystpcpy +# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE) +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +# if defined (__STDC__) || defined (__cplusplus) +yystpcpy (char *yydest, const char *yysrc) +# else +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +# endif +{ + register char *yyd = yydest; + register const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +#endif /* !YYERROR_VERBOSE */ + + + +#if YYDEBUG +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep) +#else +static void +yysymprint (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + if (yytype < YYNTOKENS) + { + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); +# ifdef YYPRINT + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + } + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + switch (yytype) + { + default: + break; + } + YYFPRINTF (yyoutput, ")"); +} + +#endif /* ! YYDEBUG */ +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +#if defined (__STDC__) || defined (__cplusplus) +static void +yydestruct (int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yytype, yyvaluep) + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + /* Pacify ``unused variable'' warnings. */ + (void) yyvaluep; + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM); +# else +int yyparse (); +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +# if defined (__STDC__) || defined (__cplusplus) +int yyparse (void *YYPARSE_PARAM) +# else +int yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +# endif +#else /* ! YYPARSE_PARAM */ +#if defined (__STDC__) || defined (__cplusplus) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + register int yystate; + register int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + short yyssa[YYINITDEPTH]; + short *yyss = yyssa; + register short *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + register YYSTYPE *yyvsp; + + + +#define YYPOPSTACK (yyvsp--, yyssp--) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* When reducing, the number of symbols on the RHS of the reduced + rule. */ + int yylen; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. + */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow ("parser stack overflow", + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyoverflowlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyoverflowlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + short *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyoverflowlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken])); + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; + + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + yystate = yyn; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 93 "expression.y" + { + DEB((D_EVENT, "[yacc] expression return %d", yyvsp[0])); + expr_result = yyvsp[0]; + ;} + break; + + case 3: +#line 99 "expression.y" + { + DEB((D_EVENT, "[yacc] elemexp return %d", yyvsp[0])); + yyval = yyvsp[0]; + ;} + break; + + case 4: +#line 104 "expression.y" + { + DEB((D_EVENT, "[yacc] not exprression %d", yyvsp[0])); + if( (yyvsp[0]) < 0 ) + yyval = 0; + else + yyval = !(yyvsp[0]); + ;} + break; + + case 5: +#line 112 "expression.y" + { + yyval = expr_check_logic(yyvsp[-2], yyvsp[-1], yyvsp[0]); + ;} + break; + + case 6: +#line 116 "expression.y" + { + DEB((D_EVENT, "eventexp: [yacc] backeted.expr %d", yyvsp[-1])); + yyval = yyvsp[-1]; + ;} + break; + + case 7: +#line 122 "expression.y" + { + yyval = expr_check_incoming(); + ;} + break; + + case 8: +#line 126 "expression.y" + { + yyval = expr_check_outgoing(); + ;} + break; + + case 9: +#line 130 "expression.y" + { + yyval = expr_check_listed(); + ;} + break; + + case 10: +#line 134 "expression.y" + { + yyval = expr_check_protected(); + ;} + break; + + case 11: +#line 138 "expression.y" + { + yyval = yyvsp[0]; + ;} + break; + + case 12: +#line 142 "expression.y" + { + if( state.valid && state.connspeed > 0 ) + yyval = expr_check_arop(state.connspeed, yyvsp[-1], yyvsp[0]); + else + yyval = -1; + ;} + break; + + case 13: +#line 149 "expression.y" + { + if( state.valid && state.node.speed > 0 ) + yyval = expr_check_arop(state.node.speed, yyvsp[-1], yyvsp[0]); + else + yyval = -1; + ;} + break; + + case 14: +#line 156 "expression.y" + { + yyval = expr_check_arop(time_gmtoffset(), yyvsp[-1], yyvsp[0]); + ;} + break; + + case 15: +#line 160 "expression.y" + { + yyval = expr_check_phone(expr_p_text); + ;} + break; + + case 16: +#line 164 "expression.y" + { + yyval = yyvsp[0]; + ;} + break; + + case 17: +#line 168 "expression.y" + { + yyval = expr_check_exec(expr_p_text); + ;} + break; + + case 18: +#line 172 "expression.y" + { + yyval = expr_check_exist(expr_p_text); + ;} + break; + + case 19: +#line 176 "expression.y" + { + yyval = expr_check_port(expr_p_text); + ;} + break; + + case 20: +#line 180 "expression.y" + { + yyval = expr_check_mailer(expr_p_text); + ;} + break; + + case 21: +#line 184 "expression.y" + { + yyval = expr_check_addr(expr_p_text); + if( yyval == -2 ) + YYABORT; + ;} + break; + + case 22: +#line 191 "expression.y" + { + yyval = expr_check_flag(expr_p_text); + ;} + break; + + case 23: +#line 195 "expression.y" + { + yyval = expr_check_logic(yyvsp[-2], OR, yyvsp[0]); + ;} + break; + + case 24: +#line 200 "expression.y" + { + yyval = expr_check_time(expr_p_text); + if( yyval == -2 ) + YYABORT; + ;} + break; + + case 25: +#line 206 "expression.y" + { + yyval = expr_check_logic(yyvsp[-2], OR, yyvsp[0]); + ;} + break; + + + } + +/* Line 991 of yacc.c. */ +#line 1287 "expression.tab.c" + + yyvsp -= yylen; + yyssp -= yylen; + + + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (YYPACT_NINF < yyn && yyn < YYLAST) + { + YYSIZE_T yysize = 0; + int yytype = YYTRANSLATE (yychar); + char *yymsg; + int yyx, yycount; + + yycount = 0; + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + yysize += yystrlen (yytname[yyx]) + 15, yycount++; + yysize += yystrlen ("syntax error, unexpected ") + 1; + yysize += yystrlen (yytname[yytype]); + yymsg = (char *) YYSTACK_ALLOC (yysize); + if (yymsg != 0) + { + char *yyp = yystpcpy (yymsg, "syntax error, unexpected "); + yyp = yystpcpy (yyp, yytname[yytype]); + + if (yycount < 5) + { + yycount = 0; + for (yyx = yyn < 0 ? -yyn : 0; + yyx < (int) (sizeof (yytname) / sizeof (char *)); + yyx++) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + const char *yyq = ! yycount ? ", expecting " : " or "; + yyp = yystpcpy (yyp, yyq); + yyp = yystpcpy (yyp, yytname[yyx]); + yycount++; + } + } + yyerror (yymsg); + YYSTACK_FREE (yymsg); + } + else + yyerror ("syntax error; also virtual memory exhausted"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror ("syntax error"); + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + /* Return failure if at end of input. */ + if (yychar == YYEOF) + { + /* Pop the error token. */ + YYPOPSTACK; + /* Pop the rest of the stack. */ + while (yyss < yyssp) + { + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[*yyssp], yyvsp); + YYPOPSTACK; + } + YYABORT; + } + + YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc); + yydestruct (yytoken, &yylval); + yychar = YYEMPTY; + + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab2; + + +/*----------------------------------------------------. +| yyerrlab1 -- error raised explicitly by an action. | +`----------------------------------------------------*/ +yyerrlab1: + + /* Suppress GCC warning that yyerrlab1 is unused when no action + invokes YYERROR. */ +#if defined (__GNUC_MINOR__) && 2093 <= (__GNUC__ * 1000 + __GNUC_MINOR__) \ + && !defined __cplusplus + __attribute__ ((__unused__)) +#endif + + + goto yyerrlab2; + + +/*---------------------------------------------------------------. +| yyerrlab2 -- pop states until the error token can be shifted. | +`---------------------------------------------------------------*/ +yyerrlab2: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp); + yydestruct (yystos[yystate], yyvsp); + yyvsp--; + yystate = *--yyssp; + + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + YYDPRINTF ((stderr, "Shifting error token, ")); + + *++yyvsp = yylval; + + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*----------------------------------------------. +| yyoverflowlab -- parser overflow comes here. | +`----------------------------------------------*/ +yyoverflowlab: + yyerror ("parser stack overflow"); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + return yyresult; +} + + +#line 210 "expression.y" + + +#include "expression_lex.c" + +static int expr_check_incoming(void) +{ + if( !state.valid ) + return -1; + + return state.caller ? 0 : 1; +} + +static int expr_check_outgoing(void) +{ + if( !state.valid ) + return -1; + + return state.caller ? 1 : 0; +} + +static int expr_check_protected(void) +{ + if( !state.valid || !state.node.addr.zone ) + return -1; + + return state.protected ? 1 : 0; +} + +static int expr_check_listed(void) +{ + if( !state.valid || !state.node.addr.zone ) + return -1; + + return state.node.listed ? 1 : 0; +} + +static int expr_check_logic(int e1, int op, int e2) +{ + DEB((D_EVENT, "[yacc] logic: %d %d %d", e1, op, e2)); + + if( e1 < 0 ) e1 = 0; + if( e2 < 0 ) e2 = 0; + + switch(op) { + case AND: + return (e1 && e2); + case OR: + return (e1 || e2); + case XOR: + return (e1 ^ e2); + } + + log("invalid logical operator in expression"); + + return 0; +} + +static int expr_check_phone(const char *phone) +{ + DEB((D_EVENT, "[yacc] phone: is %s in %s", + phone, state.node.phone)); + + if( !state.valid ) + return 0; + + return strstr(state.node.phone, phone) ? 1 : 0; +} + +static int expr_check_arop(int num1, int op, int num2) +{ + DEB((D_EVENT, "[yacc] arop: %d %d %d", num1, op, num2)); + + switch(op) { + case EQ: return (num1 == num2); + case NE: return (num1 != num2); + case GT: return (num1 > num2); + case GE: return (num1 >= num2); + case LT: return (num1 < num2); + case LE: return (num1 <= num2); + } + + log("invalid arithmetic operator in expression"); + + return 0; +} + +static int expr_check_flag(const char *str) +{ + DEB((D_EVENT, "[yacc] flag: \"%s\"", str)); + + if( !state.valid ) + return 0; + + return !nodelist_checkflag(state.node.flags, str); +} + +static int expr_check_exec(const char *str) +{ + DEB((D_EVENT, "[yacc] exec: \"%s\"", str)); + + return session_run_command(str) ? 0 : 1; +} + +static int expr_check_exist(const char *str) +{ + DEB((D_EVENT, "[yacc] exist: \"%s\"", str)); + + return access(str, F_OK) ? 1 : 0; +} + +static int expr_check_port(const char *str) +{ + DEB((D_EVENT, "[yacc] port: \"%s\"", str)); + + if( !state.valid ) + return -1; + + if( !strcasecmp(str, "tcpip") ) + { + return state.inet ? 1 : 0; + } + else if( state.modemport && state.modemport->name ) + { + return strstr(state.modemport->name, str) ? 1 : 0; + } + else if( isatty(0) ) + { + return strstr(ttyname(0), str) ? 1 : 0; + } + + return -1; +} + +static int expr_check_mailer(const char *str) +{ + char *p; + + DEB((D_EVENT, "[yacc] mailer: \"%s\"", str)); + + if( !state.valid ) + return -1; + + if( state.handshake && state.handshake->remote_mailer ) + p = state.handshake->remote_mailer(state.handshake); + else + return -1; + + return (p && string_casestr(p, str)) ? 1 : 0; +} + +static int expr_check_addr(const char *str) +{ + s_faddr addr; +#ifdef DEBUG + char abuf1[BF_MAXADDRSTR+1]; + char abuf2[BF_MAXADDRSTR+1]; + + DEB((D_EVENT, "[yacc] addr: \"%s\" (session with \"%s\")", + ftn_addrstr(abuf1, addr), + ftn_addrstr(abuf2, state.node.addr))); +#endif + + if( !state.valid ) + return -1; + + if( ftn_addrparse(&addr, str, TRUE) ) + { + log("invalid address \"%s\"", str); + return -2; + } + + return !ftn_addrcomp_mask(state.node.addr, addr); +} + +static int expr_check_time(const char *str) +{ + DEB((D_EVENT, "[yacc] time: \"%s\"", str)); + + switch( time_check(str, now) ) { + case -1: + log("invalid time string \"%s\"", str); + return -2; + case 0: + return 1; + } + + return 0; +} + +bool eventexpr(s_expr *expr) +{ + time_t tt; + char *tmp; + + if( !expr || !expr->expr ) + return 1; + + if( expr->error ) + return 0; + + DEB((D_EVENT, "eventexpr: [yacc] check expression \"%s\"", + expr->expr)); + + tt = time(NULL); + now = localtime(&tt); + tmp = (char*)xstrcpy(expr->expr); + + expr_p_pos = tmp; + expr_result = 0; + + if( yyparse() ) + { + expr->error = TRUE; + + log("cannot parse expression \"%s\"", expr->expr); + DEB((D_EVENT, "eventexpr: [yacc] $yyparse return error")); + + expr_result = 0; + } + + free(tmp); + + DEB((D_EVENT, "eventexpr: [yacc] checking result is \"%s\" (%d)", + (expr_result == 1) ? "TRUE" : "FALSE", expr_result)); + + return (expr_result == 1) ? TRUE : FALSE; +} + +static int yyerror(const char *str) +{ + log("expression check failure: %s", str); + + return 0; +} + + diff --git a/source/bforce/expression.y b/source/bforce/expression.y new file mode 100644 index 0000000..494bf65 --- /dev/null +++ b/source/bforce/expression.y @@ -0,0 +1,443 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +%token COMMA +%token TEXT +%token NUMBER +%token INCOMING +%token OUTGOING +%token LISTED +%token PROTECTED +%token CONNSPEED +%token EXEC +%token EXIST +%token PORT +%token MAILER +%token TZ +%token FLAG +%token SPEED +%token PHONE +%token TIME +%token ADDRESS +%token EQ +%token NE +%token GT +%token GE +%token LT +%token LE +%token AND +%token OR +%token NOT +%token XOR +%token OPENB +%token CLOSEB +%token AROP +%token LOGOP + +%expect 2 +%{ +#include "includes.h" +#include "confread.h" +#include "util.h" +#include "logger.h" +#include "session.h" +#include "nodelist.h" +#include "io.h" + +static struct tm *now = NULL; +static int expr_result = 0; +static char *expr_p_pos = NULL; +static char *expr_p_text = NULL; + +/* + * These are expression element checkers (not only) + * Return values: + * 0 - FALSE + * 1 - TRUE + * -1 - cannot check, because some data is not available yet + * -2 - invalid element (we should not check this expression more) + */ +static int expr_check_incoming(void); +static int expr_check_outgoing(void); +static int expr_check_protected(void); +static int expr_check_listed(void); +static int expr_check_logic(int e1, int op, int e2); +static int expr_check_phone(const char *phone); +static int expr_check_arop(int num1, int op, int num2); +static int expr_check_flag(const char *str); +static int expr_check_exec(const char *str); +static int expr_check_exist(const char *str); +static int expr_check_port(const char *str); +static int expr_check_mailer(const char *str); +static int expr_check_addr(const char *str); +static int expr_check_time(const char *str); + +static int yylex(void); +static int yyparse(void); +static int yyerror(const char *s); + +%} + +%% +fullline : expression + { + DEB((D_EVENT, "[yacc] expression return %d", $1)); + expr_result = $1; + } + ; +expression : elemexp + { + DEB((D_EVENT, "[yacc] elemexp return %d", $1)); + $$ = $1; + } +| NOT expression + { + DEB((D_EVENT, "[yacc] not exprression %d", $2)); + if( ($2) < 0 ) + $$ = 0; + else + $$ = !($2); + } +| expression LOGOP expression + { + $$ = expr_check_logic($1, $2, $3); + } +| OPENB expression CLOSEB + { + DEB((D_EVENT, "eventexp: [yacc] backeted.expr %d", $2)); + $$ = $2; + } + ; +elemexp : INCOMING + { + $$ = expr_check_incoming(); + } +| OUTGOING + { + $$ = expr_check_outgoing(); + } +| LISTED + { + $$ = expr_check_listed(); + } +| PROTECTED + { + $$ = expr_check_protected(); + } +| FLAG flagstring + { + $$ = $2; + } +| CONNSPEED AROP NUMBER + { + if( state.valid && state.connspeed > 0 ) + $$ = expr_check_arop(state.connspeed, $2, $3); + else + $$ = -1; + } +| SPEED AROP NUMBER + { + if( state.valid && state.node.speed > 0 ) + $$ = expr_check_arop(state.node.speed, $2, $3); + else + $$ = -1; + } +| TZ AROP NUMBER + { + $$ = expr_check_arop(time_gmtoffset(), $2, $3); + } +| PHONE TEXT + { + $$ = expr_check_phone(expr_p_text); + } +| TIME timestring + { + $$ = $2; + } +| EXEC TEXT + { + $$ = expr_check_exec(expr_p_text); + } +| EXIST TEXT + { + $$ = expr_check_exist(expr_p_text); + } +| PORT TEXT + { + $$ = expr_check_port(expr_p_text); + } +| MAILER TEXT + { + $$ = expr_check_mailer(expr_p_text); + } +| TEXT + { + $$ = expr_check_addr(expr_p_text); + if( $$ == -2 ) + YYABORT; + } + ; +flagstring : TEXT + { + $$ = expr_check_flag(expr_p_text); + } +| TEXT COMMA flagstring + { + $$ = expr_check_logic($1, OR, $3); + } + ; +timestring : TEXT + { + $$ = expr_check_time(expr_p_text); + if( $$ == -2 ) + YYABORT; + } +| TEXT COMMA timestring + { + $$ = expr_check_logic($1, OR, $3); + } + ; +%% + +#include "expression_lex.c" + +static int expr_check_incoming(void) +{ + if( !state.valid ) + return -1; + + return state.caller ? 0 : 1; +} + +static int expr_check_outgoing(void) +{ + if( !state.valid ) + return -1; + + return state.caller ? 1 : 0; +} + +static int expr_check_protected(void) +{ + if( !state.valid || !state.node.addr.zone ) + return -1; + + return state.protected ? 1 : 0; +} + +static int expr_check_listed(void) +{ + if( !state.valid || !state.node.addr.zone ) + return -1; + + return state.node.listed ? 1 : 0; +} + +static int expr_check_logic(int e1, int op, int e2) +{ + DEB((D_EVENT, "[yacc] logic: %d %d %d", e1, op, e2)); + + if( e1 < 0 ) e1 = 0; + if( e2 < 0 ) e2 = 0; + + switch(op) { + case AND: + return (e1 && e2); + case OR: + return (e1 || e2); + case XOR: + return (e1 ^ e2); + } + + log("invalid logical operator in expression"); + + return 0; +} + +static int expr_check_phone(const char *phone) +{ + DEB((D_EVENT, "[yacc] phone: is %s in %s", + phone, state.node.phone)); + + if( !state.valid ) + return 0; + + return strstr(state.node.phone, phone) ? 1 : 0; +} + +static int expr_check_arop(int num1, int op, int num2) +{ + DEB((D_EVENT, "[yacc] arop: %d %d %d", num1, op, num2)); + + switch(op) { + case EQ: return (num1 == num2); + case NE: return (num1 != num2); + case GT: return (num1 > num2); + case GE: return (num1 >= num2); + case LT: return (num1 < num2); + case LE: return (num1 <= num2); + } + + log("invalid arithmetic operator in expression"); + + return 0; +} + +static int expr_check_flag(const char *str) +{ + DEB((D_EVENT, "[yacc] flag: \"%s\"", str)); + + if( !state.valid ) + return 0; + + return !nodelist_checkflag(state.node.flags, str); +} + +static int expr_check_exec(const char *str) +{ + DEB((D_EVENT, "[yacc] exec: \"%s\"", str)); + + return session_run_command(str) ? 0 : 1; +} + +static int expr_check_exist(const char *str) +{ + DEB((D_EVENT, "[yacc] exist: \"%s\"", str)); + + return access(str, F_OK) ? 1 : 0; +} + +static int expr_check_port(const char *str) +{ + DEB((D_EVENT, "[yacc] port: \"%s\"", str)); + + if( !state.valid ) + return -1; + + if( !strcasecmp(str, "tcpip") ) + { + return state.inet ? 1 : 0; + } + else if( state.modemport && state.modemport->name ) + { + return strstr(state.modemport->name, str) ? 1 : 0; + } + else if( isatty(0) ) + { + return strstr(ttyname(0), str) ? 1 : 0; + } + + return -1; +} + +static int expr_check_mailer(const char *str) +{ + char *p; + + DEB((D_EVENT, "[yacc] mailer: \"%s\"", str)); + + if( !state.valid ) + return -1; + + if( state.handshake && state.handshake->remote_mailer ) + p = state.handshake->remote_mailer(state.handshake); + else + return -1; + + return (p && string_casestr(p, str)) ? 1 : 0; +} + +static int expr_check_addr(const char *str) +{ + s_faddr addr; +#ifdef DEBUG + char abuf1[BF_MAXADDRSTR+1]; + char abuf2[BF_MAXADDRSTR+1]; + + DEB((D_EVENT, "[yacc] addr: \"%s\" (session with \"%s\")", + ftn_addrstr(abuf1, addr), + ftn_addrstr(abuf2, state.node.addr))); +#endif + + if( !state.valid ) + return -1; + + if( ftn_addrparse(&addr, str, TRUE) ) + { + log("invalid address \"%s\"", str); + return -2; + } + + return !ftn_addrcomp_mask(state.node.addr, addr); +} + +static int expr_check_time(const char *str) +{ + DEB((D_EVENT, "[yacc] time: \"%s\"", str)); + + switch( time_check(str, now) ) { + case -1: + log("invalid time string \"%s\"", str); + return -2; + case 0: + return 1; + } + + return 0; +} + +bool eventexpr(s_expr *expr) +{ + time_t tt; + char *tmp; + + if( !expr || !expr->expr ) + return 1; + + if( expr->error ) + return 0; + + DEB((D_EVENT, "eventexpr: [yacc] check expression \"%s\"", + expr->expr)); + + tt = time(NULL); + now = localtime(&tt); + tmp = (char*)xstrcpy(expr->expr); + + expr_p_pos = tmp; + expr_result = 0; + + if( yyparse() ) + { + expr->error = TRUE; + + log("cannot parse expression \"%s\"", expr->expr); + DEB((D_EVENT, "eventexpr: [yacc] $yyparse return error")); + + expr_result = 0; + } + + free(tmp); + + DEB((D_EVENT, "eventexpr: [yacc] checking result is \"%s\" (%d)", + (expr_result == 1) ? "TRUE" : "FALSE", expr_result)); + + return (expr_result == 1) ? TRUE : FALSE; +} + +static int yyerror(const char *str) +{ + log("expression check failure: %s", str); + + return 0; +} diff --git a/source/bforce/expression_lex.c b/source/bforce/expression_lex.c new file mode 100644 index 0000000..3d53387 --- /dev/null +++ b/source/bforce/expression_lex.c @@ -0,0 +1,174 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +typedef struct lextable { +const char *str; + int value; + int retc; + int len; +} s_lextable; + +static bool initialised = FALSE; +static s_lextable *next = NULL; + +static s_lextable operators[] = +{ + { "==", EQ, AROP, 0 }, + { "!=", NE, AROP, 0 }, + { ">", GT, AROP, 0 }, + { ">=", GE, AROP, 0 }, + { "<", LT, AROP, 0 }, + { "<=", LE, AROP, 0 }, + { "(", OPENB, OPENB, 0 }, + { ")", CLOSEB, CLOSEB, 0 }, + { "&&", AND, LOGOP, 0 }, + { "&", AND, LOGOP, 0 }, + { "||", OR, LOGOP, 0 }, + { "|", OR, LOGOP, 0 }, + { "Xor", XOR, LOGOP, 0 }, + { "!", NOT, NOT, 0 }, + { ",", COMMA, COMMA, 0 }, + { NULL, 0, 0, 0 } +}; + +s_lextable elements[] = +{ + { "TZ", TZ, TZ, 0 }, + { "Address", ADDRESS, ADDRESS, 0 }, + { "Time", TIME, TIME, 0 }, + { "Phone", PHONE, PHONE, 0 }, + { "Flag", FLAG, FLAG, 0 }, + { "Incoming", INCOMING, INCOMING, 0 }, + { "Outgoing", OUTGOING, OUTGOING, 0 }, + { "Listed", LISTED, LISTED, 0 }, + { "Protected", PROTECTED, PROTECTED, 0 }, + { "Connspeed", CONNSPEED, CONNSPEED, 0 }, + { "Exec", EXEC, EXEC, 0 }, + { "Exist", EXIST, EXIST, 0 }, + { "Port", PORT, PORT, 0 }, + { "Mailer", MAILER, MAILER, 0 }, + { NULL, 0, 0, 0 } +}; + +static void expr_inittables(void) +{ + int i; + + for( i = 0; operators[i].str; i++ ) + operators[i].len = strlen(operators[i].str); + + for( i = 0; elements[i].str; i++ ) + elements[i].len = strlen(elements[i].str); +} + +static int yylex(void) +{ + int i, retc = 0; + s_lextable *entry = NULL; + + ASSERT(expr_p_pos != NULL); + + if( !initialised ) + { expr_inittables(); initialised = TRUE; } + + if( next ) + { + /* + * Found operator left from previous call to yylex() + */ + yylval = next->value; + DEB((D_EVENT, "yylex: got next \"%s\", yylval = %d, ret = %d", + next->str, next->value, next->retc)); + retc = next->retc; + next = NULL; + return retc; + } + + while( isspace(*expr_p_pos) ) expr_p_pos++; + + if( *expr_p_pos == '\0' ) return 0; + + for( i = 0; operators[i].str; i++ ) + { + if( strncasecmp(expr_p_pos, operators[i].str, operators[i].len) == 0 ) + { entry = &operators[i]; break; } + } + + if( entry == NULL ) + { + for( i = 0; elements[i].str; i++ ) + { + if( strncasecmp(expr_p_pos, elements[i].str, elements[i].len) == 0 ) + { entry = &elements[i]; break; } + } + } + + if( entry ) + { + expr_p_pos += entry->len; + yylval = entry->value; + DEB((D_EVENT, "yylex: got token \"%s\", yylval = %d, ret = %d", + entry->str, entry->value, entry->retc)); + return entry->retc; + } + else + { + + if( *expr_p_pos == '"' ) + { + expr_p_text = ++expr_p_pos; + + while( *expr_p_pos != '"' && *expr_p_pos ) + ++expr_p_pos; + } + else + { + expr_p_text = expr_p_pos++; + + while( !isspace(*expr_p_pos) && *expr_p_pos ) + { + for( i = 0; operators[i].str; i++ ) + if( strncasecmp(expr_p_pos, operators[i].str, operators[i].len) == 0 ) + { + next = &operators[i]; + goto enough; + } + expr_p_pos++; + } + } + +enough: + if( *expr_p_pos ) + { + *expr_p_pos = '\0'; + if( next && next->len > 1 ) + expr_p_pos += next->len; + else + expr_p_pos += 1; + } + + if( ISDEC(expr_p_text) ) + { + /* It is decimal number */ + yylval = atol(expr_p_text); + DEB((D_EVENT, "yylex: got NUMBER %d", yylval)); + return NUMBER; + } + else + { + /* It is text */ + DEB((D_EVENT, "yylex: got TEXT \"%s\"", expr_p_text)); + return(yylval = TEXT); + } + } +} diff --git a/source/bforce/freq_bark.c b/source/bforce/freq_bark.c new file mode 100644 index 0000000..dcefeec --- /dev/null +++ b/source/bforce/freq_bark.c @@ -0,0 +1,18 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "freq.h" diff --git a/source/bforce/freq_proc.c b/source/bforce/freq_proc.c new file mode 100644 index 0000000..06e57f4 --- /dev/null +++ b/source/bforce/freq_proc.c @@ -0,0 +1,406 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "outbound.h" +#include "freq.h" + +static void deinit_reqlist(s_reqlist *dest); +static void deinit_frlist(s_frlist *dest); + +/* ------------------------------------------------------------------------- */ +/* Log requested files, passwords and other specified information */ +/* ------------------------------------------------------------------------- */ +static void req_logreqlist(s_reqlist *reqlist) +{ + s_reqlist *rlist; + char *p = NULL; + char buf[100]; + + for( rlist = reqlist; rlist; rlist = rlist->next ) + { + if( rlist->fmask == NULL ) continue; + + p = xstrcpy("requested \""); + p = xstrcat(p, rlist->fmask); + p = xstrcat(p, "\""); + if( rlist->passwd ) + { + p = xstrcat(p, ", password \""); + p = xstrcat(p, rlist->passwd); + p = xstrcat(p, "\""); + } + if( rlist->newer ) + { + p = xstrcat(p, ", newer \""); + p = xstrcat(p, time_string_long(buf, sizeof(buf), rlist->newer)); + p = xstrcat(p, "\""); + } + if( rlist->older ) + { + p = xstrcat(p, ", older \""); + p = xstrcat(p, time_string_long(buf, sizeof(buf), rlist->older)); + p = xstrcat(p, "\""); + } + log("FREQ: %s", string_printable(p)); + if( p ) { free(p); p = NULL; } + } +} + +/* ------------------------------------------------------------------------- */ +/* Read files containing list of public dirs and file aliases */ +/* ------------------------------------------------------------------------- */ +static void req_readfrlist(char *fname, s_frlist **frlist, int magic) +{ + FILE *fp; + s_frlist **ptrl; + char sbuf[BF_MAXREQLINE+1]; + char *magc = NULL; + char *path = NULL; + char *pwd = NULL; + char *n = NULL; + + DEB((D_FREQ, "req_readfrlist: reading \"%s\", magic = %d", fname, magic)); + + if( (fp = file_open(fname, "r")) == NULL ) + { + logerr("FREQ: can't open dirlist \"%s\"", fname); + return; + } + + for( ptrl = frlist; *ptrl; ptrl = &(*ptrl)->next ) + { + /* EMPTY LOOP */ + } + + while( fgets(sbuf, sizeof(sbuf), fp) ) + { + string_chomp(sbuf); + + if( *sbuf == '#' ) continue; + + if( magic ) + { + magc = string_token(sbuf, &n, NULL, 1); + path = string_token(NULL, &n, NULL, 1); + } + else + { + path = string_token(sbuf, &n, NULL, 1); + } + + pwd = string_token(NULL, &n, NULL, 1); + + /* make sure it is password */ + if( pwd && *pwd == '!' ) pwd++; else pwd = NULL; + + if( path && *path && (!magic || (magc && *magc)) ) + { + DEB((D_FREQ, "req_readfrlist: add path = \"%s\", magic = \"%s\", passwd = \"%s\"", + path, magc, pwd)); + + (*ptrl) = (s_frlist*)xmalloc(sizeof(s_frlist)); + memset(*ptrl, '\0', sizeof(s_frlist)); + + if( path && *path ) (*ptrl)->path = xstrcpy(path); + if( !magic && *(path + strlen(path) - 1) != DIRSEPCHR ) + { + /* add trailing DIRSEP ('/' or ..) to paths */ + (*ptrl)->path = xstrcat((*ptrl)->path, DIRSEPSTR); + } + if( magc && *magc ) (*ptrl)->magic = xstrcpy(magc); + if( pwd && *pwd ) (*ptrl)->passwd = xstrcpy(pwd); + ptrl = &(*ptrl)->next; + } + } + + file_close(fp); +} + +/* ------------------------------------------------------------------------- */ +/* Add files to send files list, check limits. Return non-zero value */ +/* if can't send more files. */ +/* ------------------------------------------------------------------------- */ +static int req_addfile(char *fname, s_freq *freq) +{ + struct stat st; + + DEB((D_FREQ, "req_addfile: try to add \"%s\"", fname)); + + if( stat(fname, &st) ) + { + logerr("FREQ: can't stat requested file \"%s\"", fname); + } + else + { + if( S_ISREG(st.st_mode) == 0 ) + { + log("FREQ: requested file isn't regular \"%s\"", fname); + } + else if( (freq->sizelimit > 0) + && ((freq->fsize + st.st_size) > freq->sizelimit) ) + { + DEB((D_FREQ, "req_addfile:sending FREQ file \"%s\" exceed size limit", fname)); + } + else + { + freq->fnumber += 1; + freq->fsize += st.st_size; + + log("FREQ: send \"%s\", %d byte(s)", fname, st.st_size); + + (*freq->flast) = (s_filelist*)xmalloc(sizeof(s_filelist)); + memset(*freq->flast, '\0', sizeof(s_filelist)); + (*freq->flast)->fname = fname ? xstrcpy(fname) : NULL; + (*freq->flast)->size = st.st_size; + (*freq->flast)->type = TYPE_REQANSW; + (*freq->flast)->status = STATUS_WILLSEND; + (*freq->flast)->action = ACTION_NOTHING; + freq->flast = &(*freq->flast)->next; + } + } + + if( (freq->fileslimit > 0) && (freq->fnumber >= freq->fileslimit) ) + { + log("FREQ: reached files number limit (%d file(s))", freq->fileslimit); + return(1); + } + return(0); +} + +/* ------------------------------------------------------------------------- */ +/* Return non-zero if got incorrect password for password protected file */ +/* ------------------------------------------------------------------------- */ +static int checkpasswd(char *ourpwd, char *gotpwd) +{ + if( ourpwd == NULL || *ourpwd == '\0' ) return(0); + if( gotpwd && strcasecmp(ourpwd, gotpwd) == 0 ) return(0); + + return(1); +} + +/* ------------------------------------------------------------------------- */ +/* Run external (SRIF compartible) FREQ processor */ +/* ------------------------------------------------------------------------- */ +static void req_proc_ext(s_freq *freq, char *reqname) +{ + char srfname[L_tmpnam+5]; + char rspname[L_tmpnam+5]; + char *comline = NULL; + + if( tmpnam(srfname) ) + { + strncpy(rspname, srfname, L_tmpnam+4); + rspname[L_tmpnam+4] = '\0'; + strcat(srfname, ".srf"); + strcat(rspname, ".rsp"); + if( req_createsrif(srfname, reqname, rspname) == 0 ) + { + comline = xstrcpy(freq->srifproc); + comline = xstrcat(comline, " "); + comline = xstrcat(comline, srfname); + if( session_run_command(comline) == 0 ) + { + req_addfilelist(rspname, freq); + } + unlink(srfname); + unlink(rspname); + if( comline ) { free(comline); } + } + } + else + { + logerr("FREQ: can't generate temp name for SRIF"); + } +} + +/* ------------------------------------------------------------------------- */ +/* Run internal FREQ processor */ +/* ------------------------------------------------------------------------- */ +static void req_proc_int(s_freq *freq) +{ + s_reqlist *rlist; + s_frlist *frl; + struct dirent *dirent; + DIR *dirp; + char *fname = NULL; + int stop = 0; /* Stop processing FREQs */ + int msg = 0; /* Show "incorrect password" message only once */ + + for( frl = freq->frlist; !stop && frl; frl = frl->next ) + { + if( frl->magic && *frl->magic ) + { + /* MAGIC */ + DEB((D_FREQ, "req_proc_int: checking our magic \"%s\"", frl->magic)); + + for( rlist = freq->reqlist; rlist; rlist = rlist->next ) + { + if( !strcasecmp(frl->magic, rlist->fmask) ) + { + if( 0 == checkpasswd(frl->passwd, rlist->passwd) ) + { + rlist->skip = 1; + stop = req_addfile(frl->path, freq); + } + else + { + log("FREQ: incorrect password for magic \"%s\"", frl->magic); + } + break; + } + } + if( stop == 0 ) + { + /* Check - may be there is no more */ + /* requests - so break it out */ + for( rlist = freq->reqlist; rlist; rlist = rlist->next ) + { + if( rlist->skip == 0 ) break; + } + stop = (rlist == NULL); + } + } + else if( frl->path && *frl->path ) + { + /* FREQ DIR */ + if( (dirp = opendir(frl->path)) == NULL ) + { + logerr("FREQ: can't open freq dir \"%s\"", frl->path); + } + else + { + /* REGULAR DIR */ + DEB((D_FREQ, "req_proc_int: checking dir \"%s\"", frl->path)); + + while( !stop && (dirent = readdir(dirp)) ) + { + if( *dirent->d_name == '.' ) continue; + for( rlist = freq->reqlist; rlist; rlist = rlist->next ) + { + if( rlist->skip == 0 + && 0 == strcasemask(dirent->d_name, rlist->fmask) ) + { + if( 0 == checkpasswd(frl->passwd, rlist->passwd) ) + { + fname = xstrcpy(frl->path); + fname = xstrcat(fname, dirent->d_name); + stop = req_addfile(fname, freq); + free(fname); + } + else if( msg == 0 ) + { + log("FREQ: incorrect password"); + ++msg; + } + break; + } + } + } + closedir(dirp); + } + } + } +} + +/* ------------------------------------------------------------------------- */ +/* Start FREQs processing, run int. or ext. processor */ +/* ------------------------------------------------------------------------- */ +void req_proc(char *reqname, s_filelist **filelist) +{ + char *p = NULL; + time_t timer = time(NULL); + s_freq freq; + + /* Init FREQ information structure */ + memset(&freq, '\0', sizeof(s_freq)); + freq.fileslimit = conf_number(cf_freq_limit_number); + freq.sizelimit = conf_number(cf_freq_limit_size); + freq.filelist = filelist; + freq.flast = filelist; + + if( (p = conf_string(cf_freq_srif_command)) && *p ) + { + /* Try external (SRIF) FREQ processor */ + log("FREQ: starting external processor"); + + freq.srifproc = xstrcpy(p); + + req_proc_ext(&freq, reqname); + + if( freq.srifproc ) + free(freq.srifproc); + } + else + { + /* Run internal FREQ processor */ + log("FREQ: starting internal processor"); + + if( req_readwazooreq(reqname, &freq.reqlist) == 0 ) + { + req_logreqlist(freq.reqlist); + + if( (p = conf_string(cf_freq_alias_list)) && *p ) + req_readfrlist(p, &freq.frlist, 1); + + if( (p = conf_string(cf_freq_dir_list)) && *p ) + req_readfrlist(p, &freq.frlist, 0); + + if( freq.frlist ) + { + req_proc_int(&freq); + deinit_frlist(freq.frlist); + } + deinit_reqlist(freq.reqlist); + } + } + + log("FREQ: stat %d file(s), %d byte(s), %d second(s)", + freq.fnumber, freq.fsize, time(NULL)-timer); + +#ifdef DEBUG + if( freq.filelist ) + log_filelist(*freq.filelist); +#endif +} + +static void deinit_reqlist(s_reqlist *dest) +{ + s_reqlist *ptrl, *next; + + for( ptrl = dest; ptrl; ptrl = next ) + { + next = ptrl->next; + if( ptrl->fmask ) free(ptrl->fmask); + if( ptrl->passwd ) free(ptrl->passwd); + free(ptrl); + } +} + +static void deinit_frlist(s_frlist *dest) +{ + s_frlist *ptrl, *next; + + for( ptrl = dest; ptrl; ptrl = next ) + { + next = ptrl->next; + if( ptrl->magic ) free(ptrl->magic); + if( ptrl->path ) free(ptrl->path); + if( ptrl->passwd ) free(ptrl->passwd); + if( ptrl->expr ) free(ptrl->expr); + free(ptrl); + } +} diff --git a/source/bforce/freq_srif.c b/source/bforce/freq_srif.c new file mode 100644 index 0000000..8b2acf1 --- /dev/null +++ b/source/bforce/freq_srif.c @@ -0,0 +1,153 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "freq.h" +#include "session.h" + +int req_createsrif(char *sname, char *req, char *rsp) +{ + FILE *fp; + char *cptr; + s_faddr *aptr; + char abuf[BF_MAXADDRSTR+1]; + + if( (fp = file_open(sname, "w")) == NULL ) + { + logerr("can't create srif file \"%s\"", sname); + return -1; + } + + switch(state.session) { + case SESSION_EMSI: + fprintf(fp, "SessionType EMSI\n"); + break; + case SESSION_BINKP: + fprintf(fp, "SessionType OTHER\n"); + break; + case SESSION_YOOHOO: + fprintf(fp, "SessionType WAZOO\n"); + break; + case SESSION_FTSC: + fprintf(fp, "SessionType FTSC0001\n"); + break; + case SESSION_UNKNOWN: + ASSERT_MSG(); + break; + } + + fprintf(fp, "Baud %ld\n", + state.connspeed ? state.connspeed : 115200); + + fprintf(fp, "Time -1\n"); + fprintf(fp, "RequestList %s\n", req); + fprintf(fp, "ResponseList %s\n", rsp); + + fprintf(fp, "RemoteStatus %s\n", + state.protected ? "PROTECTED" : "UNPROTECTED"); + + fprintf(fp, "SystemStatus %s\n", + state.listed ? "LISTED" : "UNLISTED"); + + if( state.handshake && state.handshake->remote_sysop_name + && (cptr = state.handshake->remote_sysop_name(state.handshake)) ) + fprintf(fp, "Sysop %s\n", cptr); + else + fprintf(fp, "Sysop SysOp\n"); + + if( state.handshake && state.handshake->remote_address + && (aptr = state.handshake->remote_address(state.handshake)) ) + fprintf(fp, "AKA %s\n", ftn_addrstr(abuf, *aptr)); + else + return -1; + + if( state.handshake && state.handshake->remote_system_name + && (cptr = state.handshake->remote_system_name(state.handshake)) ) + fprintf(fp, "Site %s\n", cptr); + + if( state.handshake && state.handshake->remote_location + && (cptr = state.handshake->remote_location(state.handshake)) ) + fprintf(fp, "Location %s\n", cptr); + + if( state.handshake && state.handshake->remote_phone + && (cptr = state.handshake->remote_phone(state.handshake)) ) + fprintf(fp, "Phone %s\n", cptr); + + if( state.handshake && state.handshake->remote_mailer + && (cptr = state.handshake->remote_mailer(state.handshake)) ) + fprintf(fp, "Mailer %s\n", cptr); + + file_close(fp); + + return(0); +} + +void req_addfilelist(char *listname, s_freq *freq) +{ + FILE *fp; + char fnbuf[BF_MAXPATH+1], *p; + int action = ACTION_NOTHING; + struct stat st; + + if( (fp = file_open(listname, "r")) == NULL ) + { + logerr("can't open freq answer list \"%s\" (%d)", listname, strlen(listname)); + return; + } + + while( fgets(fnbuf, sizeof(fnbuf), fp) ) + { + p = fnbuf; + action = ACTION_NOTHING; + + string_chomp(fnbuf); + + /* + * We won't remove leading and trailing spaces + */ + + if( *p == '\0' ) + continue; /* Empty line! */ + + switch(*p) { + case '=': ++p; action = ACTION_UNLINK; break; + case '+': ++p; action = ACTION_NOTHING; break; + case '-': ++p; action = ACTION_FORCEUNLINK; break; + } + + if( stat(p, &st) == 0 ) + { + DEB((D_FREQ, "adding file \"%s\", %d", p, st.st_size)); + + (*freq->flast) = (s_filelist*)xmalloc(sizeof(s_filelist)); + memset(*freq->flast, '\0', sizeof(s_filelist)); + + (*freq->flast)->fname = xstrcpy(p); + (*freq->flast)->size = st.st_size; + (*freq->flast)->action = action; + (*freq->flast)->status = STATUS_WILLSEND; + freq->flast = &(*freq->flast)->next; + + freq->fnumber += 1; + freq->fsize += st.st_size; + } + else + logerr("can't stat file from answer list \"%s\"", p); + } + + file_close(fp); +} + diff --git a/source/bforce/freq_wazoo.c b/source/bforce/freq_wazoo.c new file mode 100644 index 0000000..af8fce2 --- /dev/null +++ b/source/bforce/freq_wazoo.c @@ -0,0 +1,113 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "freq.h" + +int req_readwazooreq(char *reqname, s_reqlist **reqlist) +{ + s_reqlist **tmpl; + char s[BF_MAXPATH+1]; + char *p, *fname, *pwd = NULL, *older = NULL, *newer = NULL; + char *p_ignorelist = NULL; + FILE *fp; + + DEB((D_FREQ, "req_readreq: open '.req' file = \"%s\"", reqname)); + + if( (fp = file_open(reqname, "r")) == NULL ) + { + logerr("can't open req file \"%s\"", reqname); + return(1); + } + + /* $tmpl must point to last entry's next field */ + for( tmpl = reqlist; *tmpl; tmpl = &(*tmpl)->next ) + { + /* EMPTY LOOP */ + } + + /* Get file masks that we should ignore */ + p_ignorelist = conf_string(cf_freq_ignore_masks); + + while( fgets(s, sizeof(s), fp) ) + { + p = s; + fname = NULL; + pwd = NULL; + older = NULL; + newer = NULL; + + string_chomp(s); + + /* Remove leading spaces */ + while( isspace(*p) ) ++p; + if( *p == '\0' ) continue; /* Empty line :( */ + + /* Get file name */ + fname = p; + while( *p && !isspace(*p) ) ++p; + + if( *p ) *p++ = '\0'; + + /* Check our ignore list */ + if( p_ignorelist && *p_ignorelist && fname && *fname ) + { + if( !checkmasks(p_ignorelist, fname) ) + { + log("FREQ: ignore request \"%s\"", fname); + continue; + } + } + + /* Is there possible password or update time? */ + while( *p ) + { + /* Remove spaces between fields */ + while( isspace(*p) ) ++p; + + switch( *p ) { + case '!' : pwd = ++p; break; + case '+' : older = ++p; break; + case '-' : newer = ++p; break; + } + /* Get field */ + while( *p && !isspace(*p) ) ++p; + if( *p ) *p++ = '\0'; + } + + if( fname && *fname ) + { + DEB((D_FREQ, "req_readreq: file=\"%s\", pwd=\"%s\", newer=\"%s\", older=\"%s\"", fname, pwd, newer, older)); + + *(tmpl) = (s_reqlist*)xmalloc(sizeof(s_reqlist)); + memset(*tmpl, '\0', sizeof(s_reqlist)); + + (*tmpl)->fmask = (char*)xstrcpy(fname); + if( pwd && *pwd ) (*tmpl)->passwd = (char*)xstrcpy(pwd); + if( newer && *newer ) (*tmpl)->newer = atol(newer); + if( older && *older ) (*tmpl)->older = atol(older); + + /* prepare $tmpl for next entry */ + tmpl = &(*tmpl)->next; + } + } + + DEB((D_FREQ, "req_readreq: close '.req' file")); + + file_close(fp); + + return(0); +} diff --git a/source/bforce/io_modem.c b/source/bforce/io_modem.c new file mode 100644 index 0000000..5209239 --- /dev/null +++ b/source/bforce/io_modem.c @@ -0,0 +1,465 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "io.h" + +const char *modem_errlist[] = +{ + "No error", + "Modem return ERROR", + "Can't send string to modem", + "Modem not response", + NULL +}; + +/* ------------------------------------------------------------------------- */ +/* Get connect speed from connect string returned by modem */ +/* ------------------------------------------------------------------------- */ +long modem_getconnspeed(const char *connstr) +{ + const char *p; + + for( p = connstr; *p; p++ ) + { + if( isdigit(*p) ) + return atol(p); + } + + return 0L; +} + +bool modem_isgood_phone(const char *str) +{ + if( !str || !str[0] ) + return FALSE; + + if( str[0] == '-' && str[1] == '\0' ) + return FALSE; + + if( string_casestr(str, "unpublished") ) + return FALSE; + + if( string_casestr(str, "unknown") ) + return FALSE; + + if( string_casestr(str, "none") ) + return FALSE; + + return TRUE; +} + +/* ------------------------------------------------------------------------- */ +/* Translate phone number using given rules, returned value must be free'ed! */ +/* ------------------------------------------------------------------------- */ +char *modem_transphone(char *buffer, const char *phone, size_t buflen) +{ + const char *p; + s_cval_entry *ptrl; + + ASSERT(phone != NULL); + + DEB((D_MODEM, "translate_phone: want translate \"%s\"", phone)); + + for( ptrl = conf_first(cf_phone_translate); ptrl; + ptrl = conf_next(ptrl) ) + { + if( !ptrl->d.translate.find ) + continue; + + if( (p = strstr(phone, ptrl->d.translate.find)) ) + { + DEB((D_MODEM, "translate_phone: replace \"%s\" with \"%s\"", + ptrl->d.translate.find, ptrl->d.translate.repl)); + + strnxcpy(buffer, phone, buflen); + + if( p - phone < buflen - 1 ) + { + buffer[p - phone] = '\0'; + + if( ptrl->d.translate.repl ) + strnxcat(buffer, ptrl->d.translate.repl, buflen); + + strnxcat(buffer, p + strlen(ptrl->d.translate.find), buflen); + } + + DEB((D_MODEM, "translate_phone: result is \"%s\"", buffer)); + + return buffer; + } + } + + return strnxcpy(buffer, phone, buflen); +} + +/* ------------------------------------------------------------------------- */ +/* Send string to modem, using some control character sequences, like */ +/* '\r' - CR, '\P' - phone number, etc.. */ +/* ------------------------------------------------------------------------- */ +int modem_putstr(const char *str) +{ + const char *ptr; + int rc; + bool flushed = FALSE; + + DEB((D_MODEM, "modem_putstr: want to send \"%s\"", str)); + + rc = TTY_SUCCESS; + ptr = str; + + while( *ptr ) + { + /* Flush buffer before "special" operations */ + if( !flushed && strchr("~`^v", *ptr) ) + { + flushed = TRUE; + if( (rc = tty_flushout()) < 0 ) + return rc; + } + + switch( *ptr ) { + case '~': + sleep(1); + break; + case '`': + usleep(250000L); + break; + case '^': + rc = tio_set_dtr(0, 1); + break; + case 'v': + rc = tio_set_dtr(0, 0); + break; + case '|': + case '\r': + rc = tty_putc('\r', 2); + if( !rc && !(rc = tty_flushout()) ) + { + /* + * Make sure that we will never send + * anything to the modem immediately + * after CR + */ + /* i changed value for my modem + * (from 250000 */ + usleep(500000); + flushed = TRUE; + } + break; + case '\\': + ++ptr; + switch(*ptr) { + case '\0': + rc = tty_putc('\\', 2); + break; + case 'r': + rc = tty_putc('\r', 2); + break; + case 'n': + rc = tty_putc('\n', 2); + break; + default: + rc = tty_putc(*ptr, 2); + } + flushed = FALSE; + break; + default: + rc = tty_putc(*ptr, 2); + flushed = FALSE; + } + + if( rc < 0 ) + return rc; + + ++ptr; + } + + if( !flushed && (rc = tty_flushout()) < 0 ) + return rc; + + return 0; +} + +void modem_clearin(int timeout) +{ + time_t timer; + + timer_set(&timer, timeout); + + while( CHARWAIT(1) ) + { + CLEARIN(); + + if( timer_expired(timer) ) + return; + + usleep(100000); /* 0.1 seconds delay */ + } +} + +/* ------------------------------------------------------------------------- */ +/* Reads in at most one less than $bufsize characters from modem and */ +/* stores them into the buffer pointed to by $buf, check for timeout. */ +/* $timer must be set with tty_settimer() call! */ +/* ------------------------------------------------------------------------- */ +int modem_getline(char *buf, int bufsize, time_t timer) +{ + int rc = 0, pos = 0; + + ASSERT(buf != NULL || bufsize == 0); + + while(1) + { + if( timer_expired(timer) ) + return TTY_TIMEOUT; + + if( (rc = tty_getc(1)) < 0 && rc != TTY_TIMEOUT ) + return rc; + else if( rc == '\r' || rc == '\n' ) + return pos; + else if( rc > 0 ) + { + if( pos < bufsize-1 ) + { + buf[pos++] = rc; + buf[pos ] = '\0'; + } else + return pos; + } + } +} + +/* ------------------------------------------------------------------------- */ +/* Dial using phone number $phone, if connection will be established - */ +/* put connect string to *connstr (must be freed) */ +/* ------------------------------------------------------------------------- */ +int modem_dial(const char *dialstr, int timeout, char **connstr) +{ + s_cval_entry *ptrl; + char buf[MODEM_MAX_RESP+1]; + time_t timer; + int len = 0; + + ASSERT(dialstr != NULL && connstr != NULL); + + *connstr = NULL; + + if( modem_putstr(dialstr) != TTY_SUCCESS ) + { + log("error sending dial string \"%s\"", dialstr); + return -1; + } + + timer_set(&timer, timeout); + + while(1) + { + if( timer_expired(timer) ) + { + log("dialing timed out"); + return -1; + } + + if( (len = modem_getline(buf, sizeof(buf), timer)) < 0 ) + { + if( len == TTY_TIMEOUT ) + log("dialing timed out"); + + return -1; + } + else if( len > 0 ) + { + DEB((D_MODEM, "modem_dial: got \"%s\"", buf)); + + for( ptrl = conf_first(cf_modem_dial_response); ptrl; + ptrl = conf_next(ptrl) ) + { + if( ptrl->d.dialresp.mstr && strstr(buf, ptrl->d.dialresp.mstr) ) + { + if( ptrl->d.dialresp.retv == RESPTYPE_CONNECT ) + { + *connstr = xstrcpy(buf); + return 0; + } + return ptrl->d.dialresp.retv; + } + } + if( *buf ) + log("modem: \"%s\"", string_printable(buf)); + } + } +} + +int modem_command(const char *command, int timeout, bool logit) +{ + time_t timer; + size_t count = 0; + int len = 0; + char buffer[MODEM_MAX_RESP+1]; + char cmdstr[MODEM_MAX_COMMAND+1]; + char *n; + char *p; + + ASSERT(command != NULL); + + strnxcpy(cmdstr, command, sizeof(cmdstr)); + + DEB((D_MODEM, "modem_command: command string \"%s\"", cmdstr)); + + CLEARIN(); + + for( p = string_token(cmdstr, &n, NULL, 1); p; + p = string_token(NULL, &n, NULL, 1) ) + { + DEB((D_MODEM, "modem_command: send \"%s\"", + string_printable(p))); + + if( modem_putstr(p) < 0 ) + return MODEM_CANTSEND; + + count = 0; + timer_set(&timer, timeout); + + while(1) + { + if( timer_expired(timer) ) + return MODEM_NORESP; + + if( (len = modem_getline(buffer, sizeof(buffer), timer)) < 0 ) + { + return MODEM_NORESP; + } + else if( len > 0 ) + { + count += len; + + if( count > MODEM_MAX_RESP_SIZE ) + { + log("modem response exceeds limit %ld bytes", + (long)count); + return MODEM_NORESP; + } + + DEB((D_MODEM, "modem_command: got \"%s\"", + string_printable(buffer))); + + if( !strcmp(buffer, "ERROR") ) + return MODEM_ERROR; + else if( !strcmp(buffer, "OK") ) + break; + else if( logit ) + log("modem: \"%s\"", string_printable(buffer)); + } + } + } + + return MODEM_OK; +} + +int modem_hangup(const char *command, int timeout) +{ +#ifdef MODEM_HANGUP_WATCH_CARRIER + time_t timer; + + ASSERT(command != NULL); + + if( tio_get_dcd(0) == 1 ) + { + DEB((D_MODEM, "modem_hangup: send \"%s\"", command)); + + if( modem_putstr(command) < 0 ) + return MODEM_CANTSEND; + + timer_set(&timer, timeout); + + while( tio_get_dcd(0) == 1 ) + { + if( timer_expired(timer) ) + return MODEM_NORESP; + + sleep(1); + } + } + + sleep(2); CLEARIN(); CLEAROUT(); + + return MODEM_OK; +#else /* MODEM_HANGUP_WATCH_CARRIER */ + return modem_command(command, timeout, FALSE); +#endif +} + +bool modem_candialout(const char *modemdev) +{ + char tmp[BF_MAXPATH+1]; + const char *p_nodial = conf_string(cf_nodial_flag); + char *p = NULL; + + if( p_nodial && *p_nodial ) + { + if( access(p_nodial, F_OK) == 0 ) + return FALSE; + + strnxcpy(tmp, p_nodial, sizeof(tmp)); + strnxcat(tmp, ".", sizeof(tmp)); + strnxcat(tmp, (p = port_get_name(modemdev)), sizeof(tmp)); + + if( p ) + free(p); + + if( access(tmp, F_OK) == 0 ) + return FALSE; + } + + return TRUE; +} + +/* ------------------------------------------------------------------------- */ +/* Return pointer to the first not locked now tty */ +/* ------------------------------------------------------------------------- */ +s_modemport *modem_getfree_port(const char *lockdir) +{ + s_cval_entry *ptrl; + + /* Find first not locked modem device */ + for( ptrl = conf_first(cf_modem_port); ptrl; ptrl = conf_next(ptrl) ) + { + if( port_checklock(lockdir, &ptrl->d.modemport) == LOCKCHECK_NOLOCK + && modem_candialout(ptrl->d.modemport.name) == TRUE ) + return &ptrl->d.modemport; + } + + return NULL; +} + +/* ------------------------------------------------------------------------- */ +/* Return pointer to the first tty whose name contain substring `ttyname' */ +/* ------------------------------------------------------------------------- */ +s_modemport *modem_getmatch_port(const char *substr) +{ + s_cval_entry *ptrl; + + /* Find first matching modem device */ + for( ptrl = conf_first(cf_modem_port); ptrl; ptrl = conf_next(ptrl) ) + { + if( strstr(ptrl->d.modemport.name, substr) ) + return &ptrl->d.modemport; + } + + return NULL; +} + diff --git a/source/bforce/io_tcpip.c b/source/bforce/io_tcpip.c new file mode 100644 index 0000000..0c27dc5 --- /dev/null +++ b/source/bforce/io_tcpip.c @@ -0,0 +1,250 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "io.h" + +#define DEFAULT_PORT 60179 /* Birthday .. mother fucker :) */ + +static RETSIGTYPE tcpip_interrupt(int sig) +{ + tty_abort = TRUE; + log("terminating on signal %d", sig); +} + +static RETSIGTYPE tcpip_brokenpipe(int sig) +{ + tty_abort = TRUE; + if( tty_online ) + log("connection closed"); + else + log("terminating on signal %d", sig); +} + +static int tcpip_connect2(struct sockaddr_in server) +{ + int fd; + + DEB((D_INFO, "tcpip_connect2: trying \"%s\" at port %d", + inet_ntoa(server.sin_addr), (int)ntohs(server.sin_port))); + + if( (fd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) + { + logerr("can't create socket"); + return(1); + } + + /* make new fd == stdin if it isn't already */ + if( fd > 0 ) + { + (void)close(0); + if( dup(fd) != 0 ) + { + logerr("cannot dup socket to stdin"); + return(1); + } + } + + /* make stdout and stderr, too */ + (void)close(1); + (void)close(2); + + if( dup(0) != 1 ) + { + logerr("cannot dup stdin to stdout"); + return(1); + } + if( dup(0) != 2 ) + { + logerr("cannot dup stdin to stderr"); + return(1); + } + + if( fd > 2 ) (void)close(fd); + + /* switch off stdio buffering */ + setbuf(stdin, (char *)NULL); + setbuf(stdout, (char *)NULL); + setbuf(stderr, (char *)NULL); + + clearerr(stdin); + clearerr(stdout); + clearerr(stderr); + + if( connect(0, (struct sockaddr*)&server, sizeof(server)) == -1 ) + { + logerr("can't connect to %s", inet_ntoa(server.sin_addr)); + close(0); + close(1); + close(2); + return 1; + } + + if( tcpip_init() ) + { + tcpip_shutdown(); + return 1; + } + + log("TCP/IP connect to %s on port %d", + inet_ntoa(server.sin_addr), (int)ntohs(server.sin_port)); + + return(0); +} + +int tcpip_connect(const char *hostname, e_tcpmode tcpmode) +{ + int rc = 0; + struct hostent *he = NULL; + struct servent *se = NULL; + struct sockaddr_in server; + char *host = xstrcpy(hostname); + char *p = strrchr(host, ':'); + const char *port = NULL; + + server.sin_family = AF_INET; + + if( p ) + { *p++ = '\0'; port = p; } + else if( tcpmode == TCPMODE_BINKP ) + port = "binkp"; + else if( tcpmode == TCPMODE_TELNET ) + port = "telnet"; + else /* Default service name is "fido" */ + port = "fido"; + + if( ISDEC(port) ) + server.sin_port = htons(atoi(port)); + else if( (se = getservbyname(port, "tcp")) ) + server.sin_port = se->s_port; + else + { log("invalid port or service name \"%s\"", port); rc = 1; } + + if( rc == 0 ) + { + if( (he = gethostbyname(host)) ) + { + memcpy(&server.sin_addr, he->h_addr, he->h_length); + } + else + { + rc = 1; + switch(h_errno) { + case HOST_NOT_FOUND: + log("host \"%s\" not found", host); + break; + case NO_ADDRESS: + log("no IP address found for host \"%s\"", host); + break; + case NO_RECOVERY: + log("non-recoverable name server error occured"); + break; + case TRY_AGAIN: + log("temporary error occured on name server"); + break; + default: + log("unknown error while resolving host \"%s\"", host); + break; + } + } + } + + if( host ) { free(host); host = NULL; } + + return rc ? rc : tcpip_connect2(server); +} + +int tcpip_init(void) +{ + int nbio_arg = 1; + int alive_arg = 1; + struct linger lingeropt; + + tty_online = TRUE; + tty_abort = FALSE; + tty_hangup = FALSE; + tty_modem = FALSE; + + /* + * Set sockets I/O to the non-blocking mode + */ + if( ioctl(0, FIONBIO, (char *)&nbio_arg, sizeof(nbio_arg)) == -1 ) + { + logerr("failed to set non-blocking mode for stdin"); + return 1; + } + + if( ioctl(1, FIONBIO, (char *)&nbio_arg, sizeof(nbio_arg)) == -1 ) + { + logerr("failed to set non-blocking mode for stdout"); + return 1; + } + + /* + * Set SO_LONGER socket option, so then we will close + * socket the system will block our close() call and + * try to deliver queued data. + */ + memset(&lingeropt, '\0', sizeof(struct linger)); + + lingeropt.l_onoff = 1; + lingeropt.l_linger = 5*100; /* 5 seconds */ + + if( setsockopt(1, SOL_SOCKET, SO_LINGER, (char*)&lingeropt, sizeof(struct linger)) == -1 ) + { + logerr("failed to set SO_LINGER socket option for the stdout"); + return 1; + } + + /* + * Set SO_KEEPALIVE socket option. The connection will be + * considered broken if remote side fail to respond on + * periodicaly transmitted message. We should not hang + * even without such features. + */ + if( setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char*)&alive_arg, sizeof(alive_arg)) == -1 ) + { + logerr("failed to set SO_KEEPALIVE socket option"); + return 1; + } + + signal(SIGHUP, tcpip_interrupt); + signal(SIGINT, tcpip_interrupt); + signal(SIGTERM, tcpip_interrupt); + signal(SIGPIPE, tcpip_brokenpipe); + + return(0); +} + +int tcpip_shutdown(void) +{ + close(0); + close(1); + close(2); + return 0; +} + +bool tcpip_isgood_host(const char *str) +{ + if( !str || !str[0] ) + return FALSE; + + if( str[0] == '-' && str[1] == '\0' ) + return FALSE; + + return TRUE; +} + diff --git a/source/bforce/io_unix_lock.c b/source/bforce/io_unix_lock.c new file mode 100644 index 0000000..4d281e1 --- /dev/null +++ b/source/bforce/io_unix_lock.c @@ -0,0 +1,379 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "io.h" + +/* + * Set lock files type: Ascii, binary or SVR4? (not implemented yet) + */ +#if (BFORCE_LOCK_TYPE == 1) +# define LOCK_ASCII +#elif (BFORCE_LOCK_TYPE == 2) +# define LOCK_BIN +#else +# error "Not implemented lock files type (BFORCE_LOCK_TYPE)" +#endif + +/* + * Set lock files directory + */ +#ifndef BFORCE_LOCK_DIR +# error "Not defined lock files directory (BFORCE_LOCK_DIR)" +#endif + +/* + * Set prefix for lock file names + */ +#ifndef BFORCE_LOCK_PREFIX +# define BFORCE_LOCK_PREFIX "LCK.." +#endif + +/* + * How much times we will try to lock (if device + * is allready locked by another process) + */ +#ifndef BFORCE_LOCK_TRIES +# define BFORCE_LOCK_TRIES 2 +#endif + +/* + * Delay in seconds between tries + */ +#ifndef BFORCE_LOCK_DELAY +# define BFORCE_LOCK_DELAY 1 +#endif + +/* ========================================================================= */ +/* "Low level" interface for tty lock files access (private) */ +/* */ +/* char *lock_getname(const char *lockdir, const s_modemport *modemport) */ +/* pid_t lock_read_pid(const char *lckname) */ +/* int lock_check(const char *lckname) */ +/* int lock_create(const char *lckname, const char *tmpname) */ +/* */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* Get lock file name with full path (this value must be free'ed) */ +/* ------------------------------------------------------------------------- */ +static char *lock_getname(const char *lockdir, const s_modemport *modemport) +{ + char *lckname; + char *p = NULL; + + ASSERT(modemport != NULL); + + if( lockdir && *lockdir ) + lckname = (char *)xstrcpy(lockdir); + else + lckname = (char *)xstrcpy(BFORCE_LOCK_DIR); + + lckname = (char *)xstrcat(lckname, BFORCE_LOCK_PREFIX); + lckname = (char *)xstrcat(lckname, (p = port_get_name(modemport->name))); + + if( p ) + free(p); + + return lckname; +} + +/* ------------------------------------------------------------------------- */ +/* Get lock file's PID. Return zero on error and leave errno with last error */ +/* ------------------------------------------------------------------------- */ +static pid_t lock_read_pid(const char *lckname) +{ + int len, fd; + pid_t pid; + char buf[32]; + + ASSERT(lckname != NULL); + + if( (fd = open(lckname, O_RDONLY)) < 0 ) + return 0; + + if( (len = read(fd, buf, sizeof(buf)-1)) < 0 ) + { + close(fd); + return 0; + } + + buf[len] = '\0'; + + if( len == sizeof(pid) || sscanf(buf, "%d", &pid) != 1 || pid == 0 ) + { + /* We found binary lock file? */ + pid = *((int *)buf); +#ifndef LOCK_BINARY + log("warning: found binary lock file %s", lckname); +#endif + } +#ifdef LOCK_BINARY + else + { + /* Found ASCII lock file */ + log("warning: found ascii lock file %s", lckname); + } +#endif + close(fd); + + return pid; +} + +/* ------------------------------------------------------------------------- */ +/* Validate lock file, check it's process still lives. */ +/* Return: */ +/* CHECKLOCK_NOLOCK - no lock file found */ +/* CHECKLOCK_LOCKED - valid lock file */ +/* CHECKLOCK_ERROR - invalid lock file name, access error, etc. */ +/* CHECKLOCK_OURLOCK - if it is our lock file (with our PID) */ +/* ------------------------------------------------------------------------- */ +static int lock_check(const char *lckname) +{ + pid_t pid = 0; + struct stat st; + + ASSERT(lckname != NULL); + + if( stat(lckname, &st) && errno == ENOENT ) + return LOCKCHECK_NOLOCK; + + if( (pid = lock_read_pid(lckname)) == 0 ) + { + if( errno == ENOENT ) + return LOCKCHECK_NOLOCK; + return LOCKCHECK_LOCKED; + } + + DEB((D_MODEM, "lock_check: lock PID = %d", pid)); + + if( pid == getpid() ) + { return LOCKCHECK_OURLOCK; } + + if( kill(pid, 0) == -1 ) + { + if( errno == ESRCH ) + { + /* + * That process no longer exists, remove lock file + */ + log("found stale lock file with PID %d", pid); + + if( unlink(lckname) == -1 ) + { + logerr("cannot remove lockfile \"%s\", lckname"); + return LOCKCHECK_ERROR; + } else + return LOCKCHECK_NOLOCK; + } + else + { + return LOCKCHECK_ERROR; + } + } + + /* locking process still lives */ + return LOCKCHECK_LOCKED; +} + +/* ------------------------------------------------------------------------- */ +/* Create lock file using link(tmpname, lckname). Return zero on success. */ +/* ------------------------------------------------------------------------- */ +static int lock_create(const char *lckname, const char *tmpname) +{ + int rc, fd; + int tries; + +#ifdef LOCK_BINARY + pid_t pid; +#else + char buf[32]; +#endif + + ASSERT(lckname != NULL && tmpname != NULL); + + if( (fd = open(tmpname, O_CREAT | O_RDWR, 0644)) < 0 ) + { + logerr("can't open temp file \"%s\"", tmpname); + return 1; + } + + chmod(tmpname, 0644); + +#ifdef LOCK_BINARY + pid = getpid(); + rc = ( write(fd, (char *)&pid, sizeof(pid)) != sizeof(pid) ); +#else + sprintf(buf, "%10d\n", (int)getpid()); + rc = ( write(fd, (char *)buf, strlen(buf)) != strlen(buf) ); +#endif + close(fd); + + if( rc ) + { + logerr("can't write PID to temp. lock file \"%s\"", tmpname); + unlink(tmpname); + return 1; + } + + for( tries = 0; tries < BFORCE_LOCK_TRIES; tries++ ) + { + if( link(tmpname, lckname) == -1 ) + { + if( errno == EEXIST ) + { + rc = lock_check(lckname); + if( rc == LOCKCHECK_ERROR ) + { + break; + } + else if( rc == LOCKCHECK_OURLOCK ) + { + /* There is our lock! :) */ + unlink(tmpname); + return 0; + } + else if( rc == LOCKCHECK_LOCKED ) + { + /* sleep some time */ + sleep(BFORCE_LOCK_DELAY); + } + } + else + { + log("can't create link to temp. lock file \"%s\"", lckname); + break; + } + } + else + { + /* Successful lock */ + unlink(tmpname); + return 0; + } + } + + /* Can't create lock file */ + unlink(tmpname); + return 1; +} + +/* ========================================================================= */ +/* PUBLIC functions for tty lock files access */ +/* */ +/* int port_checklock(const char *lockdir, const char *dev) */ +/* int port_lock(char *lockdir, char *dev) */ +/* int port_unlock(const char *lockdir, const char *dev) */ +/* */ +/* ========================================================================= */ + +/* ------------------------------------------------------------------------- */ +/* Check, is tty locked? Return one of return values of lock_check() */ +/* ------------------------------------------------------------------------- */ +int port_checklock(const char *lockdir, const s_modemport *modemport) +{ + int rc; + char *lckname; + + if( (lckname = lock_getname(lockdir, modemport)) == NULL ) + { + log("can't get lock file name"); + return LOCKCHECK_ERROR; + } + + DEB((D_MODEM, "checkttylock: lock device = \"%s\", lockfile = \"%s\"", + modemport->name, lckname)); + + rc = lock_check(lckname); + + if( lckname ) + free(lckname); + + return rc; +} + +/* ------------------------------------------------------------------------- */ +/* Lock serial port. On success return zero value */ +/* ------------------------------------------------------------------------- */ +int port_lock(const char *lockdir, const s_modemport *modemport) +{ + int rc; + char *lckname; + char *tmpname, *p_tmpname; + + if( lockdir && *lockdir ) + tmpname = xstrcpy(lockdir); + else + tmpname = xstrcpy(BFORCE_LOCK_DIR); + + tmpname = xstrcat(tmpname, "bfXXXXXX"); + + if( (p_tmpname = mktemp(tmpname)) == NULL ) + { + logerr("can't generate unique file name from \"%s\"", tmpname); + free(tmpname); return 1; + } + + if( (lckname = lock_getname(lockdir, modemport)) == NULL ) + { + log("can't get lock file name"); + return(1); + } + + DEB((D_MODEM, "locktty: lock device = \"%s\", tmpfile = \"%s\", lockfile = \"%s\"", + modemport->name, p_tmpname, lckname)); + + rc = lock_create(lckname, p_tmpname); + + if( tmpname ) + free(tmpname); + if( lckname ) + free(lckname); + + return rc; +} + +/* ------------------------------------------------------------------------- */ +/* Unlock serial port. Return zero on success. */ +/* ------------------------------------------------------------------------- */ +int port_unlock(const char *lockdir, const s_modemport *modemport) +{ + pid_t pid = 0; + char *lckname; + + if( (lckname = lock_getname(lockdir, modemport)) == NULL ) + return 1; + + DEB((D_MODEM, "unlocktty: unlock device = \"%s\", lockfile = \"%s\"", + modemport->name, lckname)); + + if( (pid = lock_read_pid(lckname)) == 0 ) + { + free(lckname); + return 1; + } + + if( pid == getpid() && unlink(lckname) == -1 ) + { + free(lckname); + return 1; + } + + free(lckname); + + return 0; +} + diff --git a/source/bforce/io_unix_modem.c b/source/bforce/io_unix_modem.c new file mode 100644 index 0000000..40fd182 --- /dev/null +++ b/source/bforce/io_unix_modem.c @@ -0,0 +1,242 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "io.h" + +/* + * Get verbal device name, remove "/dev/" part and replace all '/' + * characters by the '-' character. Returned value must be freed. + */ +char *port_get_name(const char *devname) +{ + char *yield = NULL; + + if( !devname ) + yield = xstrcpy("unknown"); + else if( !strncmp(devname, "/dev/", 5) ) + yield = xstrcpy(devname + 5); + else + yield = xstrcpy(devname); + + string_replchar(yield, '/', '-'); + + return yield; +} + +#ifndef MODEM_WATCH_CARRIER +static RETSIGTYPE linedrop(int sig) +{ + if( tty_online ) + { + log("carrier lost"); + tty_hangup = TRUE; + } + else + { + log("terminating on signal %d", sig); + tty_abort = TRUE; + } +} +#endif + +static RETSIGTYPE interrupt(int sig) +{ + tty_abort = TRUE; + log("terminating on signal %d", sig); +} + +/* + * Open modem device $port, save old termios to $oldtio + */ +int port_open(const s_modemport *port, int detach, TIO *oldtio) +{ + int fd; + + ASSERT(port != NULL); + + DEB((D_MODEM, "openport: open device \"%s\" locked at %ld", + port->name, (long)port->speed)); + + if( (fd = open(port->name, O_RDWR | O_NONBLOCK)) < 0 ) + { logerr("cannot open device \"%s\"", port->name); return 1; } + + /* make new fd == stdin if it isn't already */ + if( fd > 0 ) + { + if( detach ) + (void)close(0); + if( dup(fd) != 0 ) + { logerr("cannot make device \"%s\" stdin", port->name); return(1); } + } + + /* make stdout and stderr, too */ + if( detach ) + { (void)close(1); (void)close(2); } + + if( dup(0) != 1 ) + { logerr("cannot dup stdin to stdout"); return(1); } + + if( dup(0) != 2 ) + { logerr("cannot dup stdin to stderr"); return(1); } + + if( fd > 2 ) + (void)close(fd); + + /* Set port modes (LOCAL mode) */ + if( port_init(0, port->speed, oldtio, TRUE) ) + return(1); + + /* Make it controlling tty */ + if( detach ) + tio_ctty(0); + + /* + * Switch off stdio buffering. We are + * not going to use streamed I/O, but.. + */ + setbuf(stdin, (char *)NULL); + setbuf(stdout, (char *)NULL); + setbuf(stderr, (char *)NULL); + + return(0); +} + +/* + * Set terminal options as required. Don't forget that settings of + * the file descriptor copies made with dup() are shared. + */ +int port_init(int fd, int portspeed, TIO *oldtio, bool local) +{ + TIO tio; + + /* Install signal handlers */ +#ifdef MODEM_WATCH_CARRIER + signal(SIGHUP, interrupt); +#else + signal(SIGHUP, linedrop); +#endif + signal(SIGINT, interrupt); + signal(SIGTERM, interrupt); + + /* + * Set descriptor I/O to the non-blocking mode + */ + if( fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1 ) + { + logerr("cannot set non-blocking mode for stdin"); + return -1; + } + + if( isatty(fd) ) + { + /* Report to tty I/O routines that we are using modem */ + tty_modem = 1; + + if( tio_get(fd, &tio) == -1 ) + { + logerr("initport error: cannot get terminal settings"); + return -1; + } + + /* + * Save old settings. We will restore them on exit. + */ + if( oldtio ) + *oldtio = tio; + + /* Set "raw" mode */ + tio_set_raw_mode(&tio); + + /* Set hardware flow control */ + if( tio_set_flow_control(fd, &tio, FLOW_HARD) == -1 ) + return -1; + + /* Should we ignore DCD? */ +#ifdef MODEM_WATCH_CARRIER + tio_set_local(&tio, TRUE); +#else + tio_set_local(&tio, local); +#endif + + /* Set port speed */ + if( portspeed ) + { + /* set bit rate */ + tio_set_speed(&tio, portspeed); + } + + if( tio_set(fd, &tio) == -1 ) + { + logerr("initport error: cannot set terminal settings"); + return -1; + } + } + + return 0; +} + +int port_carrier(int fd, bool online) +{ + tty_online = online; + +#ifndef MODEM_WATCH_CARRIER + if( isatty(fd) ) + { + TIO tio; + + if( tio_get(fd, &tio) == -1 ) + { + logerr("port_carrier error: cannot get terminal settings"); + return -1; + } + + tio_set_local(&tio, online ? FALSE : TRUE); + + if( tio_set(fd, &tio) == -1 ) + { + logerr("port_carrier error: cannot set terminal settings"); + return -1; + } + } +#endif + + return 0; +} + +/* + * Restore old terminal settings + */ +int port_deinit(int fd, TIO *oldtio) +{ + if( tio_set(fd, oldtio) == -1 ) + { + logerr("deinitport error: cannot restore terminal settings"); + return -1; + } + + return 0; +} + +/* + * Close port + */ +void port_close(void) +{ + DEB((D_MODEM, "closeport: close modem port")); + /* Do nothing */ +} + diff --git a/source/bforce/io_unix_tio.c b/source/bforce/io_unix_tio.c new file mode 100644 index 0000000..91b4281 --- /dev/null +++ b/source/bforce/io_unix_tio.c @@ -0,0 +1,336 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "io.h" + +/* + * Hardware handshake flags (stolen from mgetty) + */ +#ifdef CRTSCTS +# define TIO_FLOW_HARD CRTSCTS /* linux, SunOS */ +#else +# ifdef CRTSFL +# define TIO_FLOW_HARD CRTSFL /* SCO 3.2v4.2 */ +# else +# ifdef RTSFLOW +# define TIO_FLOW_HARD RTSFLOW | CTSFLOW /* SCO 3.2v2 */ +# else +# ifdef CTSCD +# define TIO_FLOW_HARD CTSCD /* AT&T 3b1? */ +# else +# define TIO_FLOW_HARD 0 +# endif +# endif +# endif +#endif + +/* + * Software hadshake flags + */ +#define TIO_FLOW_SOFT (IXON | IXOFF) + +/* + * Supported baud rates + */ +static struct speedtab { +#ifdef HAVE_TERMIOS_H + speed_t bspeed; +#else + unsigned short bspeed; +#endif + int nspeed; +const char *speed; +} speedtab[] = { + { B300, 300, "300" }, +#ifdef B600 + { B600, 600, "600" }, +#endif +#ifdef B900 + { B900, 900, "900" }, +#endif + { B1200, 1200, "1200" }, +#ifdef B1800 + { B1800, 1800, "1800" }, +#endif + { B2400, 2400, "2400" }, +#ifdef B3600 + { B3600, 3600, "3600" }, +#endif + { B4800, 4800, "4800" }, +#ifdef B7200 + { B7200, 7200, "7200" }, +#endif + { B9600, 9600, "9600" }, +#ifdef B14400 + { B14400, 14400, "14400" }, +#endif +#ifdef B19200 + { B19200, 19200, "19200" }, +#endif /* B19200 */ +#ifdef B28800 + { B28800, 28800, "28800" }, +#endif +#ifdef B38400 + { B38400, 38400, "38400" }, +#endif /* B38400 */ +#ifdef EXTA + { EXTA, 19200, "EXTA" }, +#endif +#ifdef EXTB + { EXTB, 38400, "EXTB" }, +#endif +#ifdef B57600 + { B57600, 57600, "57600" }, +#endif +#ifdef B76800 + { B76800, 76800, "76800" }, +#endif +#ifdef B115200 + { B115200, 115200, "115200" }, +#endif +#ifdef B230400 + { B230400, 230400, "230400" }, +#endif +#ifdef B460800 + { B460800, 460800, "460800" }, +#endif + { 0, 0, "" } +}; + + +/* get current tio settings for given filedescriptor */ + +int tio_get(int fd, TIO *tio) +{ +#ifdef HAVE_TERMIOS_H + return tcgetattr(fd, tio); +#endif +} + +/* set current tio settings for given filedescriptor */ + +int tio_set(int fd, TIO *tio) +{ +#ifdef HAVE_TERMIOS_H + return tcsetattr(fd, TCSANOW, tio); +#endif +} + +int tio_set_speed(TIO *tio, unsigned int speed) +{ + int i; +#ifdef HAVE_TERMIOS_H + speed_t bspeed = -1; +#else + int bspeed = -1; +#endif + + for( i = 0; speedtab[i].nspeed; i++ ) + { + if( speedtab[i].nspeed == speed ) + { + bspeed = speedtab[i].bspeed; + break; + } + } + + if( bspeed == -1 ) + { + log("unsupported speed %d", speed); + return -1; + } + +#ifdef HAVE_TERMIOS_H + cfsetospeed(tio, bspeed); + cfsetispeed(tio, bspeed); +#endif + + return 0; +} + +/* get port speed. Return integer value, not symbolic constant */ + +int tio_get_speed(TIO *tio) +{ + int i; +#ifdef HAVE_TERMIOS_H + speed_t bspeed = cfgetospeed(tio); +#endif + + for( i = 0; speedtab[i].nspeed; i++ ) + { + if( speedtab[i].bspeed == bspeed ) + return speedtab[i].nspeed; + } + + return-1; +} + +int tio_set_flow_control(int fd, TIO *tio, int flow) +{ +#if defined(HAVE_SYS_TERMIOX_H) + struct termiox tix; +#endif + + DEB((D_MODEM, "tio_set_flow_control: setting HARD=%s, SOFT=%s", + (flow & FLOW_HARD) ? "On" : "Off", + (flow & FLOW_SOFT) ? "On" : "Off")); + +#if defined(HAVE_TERMIOS_H) + tio->c_cflag &= ~TIO_FLOW_HARD; + tio->c_iflag &= ~TIO_FLOW_SOFT; +#ifdef IXANY + tio->c_iflag &= ~IXANY; +#endif + + if( flow & FLOW_HARD ) + tio->c_cflag |= TIO_FLOW_HARD; + if( flow & FLOW_SOFT ) + tio->c_iflag |= TIO_FLOW_SOFT; +#endif /* HAVE_TERMIOS_H */ + +#if defined(HAVE_SYS_TERMIOX_H) + if( ioctl(fd, TCGETX, &tix) == -1 ) + { + logerr("failed ioctl(TCGETX)"); + return -1; + } + + if( flow & FLOW_HARD ) + tix.x_hflag |= (RTSXOFF | CTSXON); + else + tix.x_hflag &= ~(RTSXOFF | CTSXON); + + if( ioctl(fd, TCSETX, &tix) == -1 ) + { + logerr("failed ioctl(TCSETX)"); + return -1; + } +#endif /* HAVE_SYS_TERMIOX_H */ + + return 0; +} + +void tio_set_raw_mode(TIO *tio) +{ +#if defined(HAVE_TERMIOS_H) + tio->c_cflag &= ~(CSTOPB | PARENB | PARODD); + tio->c_cflag |= (CS8 | CREAD | HUPCL); + tio->c_iflag = TIO_FLOW_SOFT; + tio->c_oflag = 0; + tio->c_lflag = 0; + tio->c_cc[VMIN] = 128; + tio->c_cc[VTIME] = 1; +#endif +} + +void tio_set_local(TIO *tio, bool local) +{ +#if defined(HAVE_TERMIOS_H) + if( local ) + tio->c_cflag |= CLOCAL; + else + tio->c_cflag &= ~CLOCAL; +#endif +} + +int tio_set_dtr(int fd, bool on) +{ + int mctl = TIO_RS232_DTR; + + DEB((D_MODEM, "tio_setdtr: setting DTR = %s", on ? "On" : "Off")); + + if( on ) + { + if( ioctl(fd, TIOCMBIS, &mctl ) < 0 ) + { + logerr("cannot set DTR = On: TIOCMBIS failed"); + return -1; + } + } + else + { + if( ioctl(fd, TIOCMBIC, &mctl ) < 0 ) + { + logerr("cannot set DTR = Off: TIOCMBIC failed"); + return -1; + } + } + + return 0; +} + +int tio_ctty(int fd) +{ + if( setsid() < 0 ) + logerr("cannot make myself session leader (setsid)"); + +#ifdef TIOCSCTTY + if( ioctl(fd, TIOCSCTTY, 0) < 0 ) + { + logerr("cannot set controlling tty (ioctl)"); + return -1; + } +#endif + + return 0; +} + +int tio_send_break(void) +{ +#ifdef HAVE_TERMIOS_H + if( tcsendbreak(1, 0) < 0 ) + { + logerr("tcsendbreak(1,0) failed"); +#else + if( ioctl(1, TCSBRK) < 0 ) + { + logerr("ioctl(1,TCSBRK) failed"); +#endif + return -1; + } + return 0; +} + +int tio_get_dcd(int fd) +{ + int flags; + + if( ioctl(fd, TIOCMGET, &flags ) < 0 ) + return -1; + + return (flags & TIO_RS232_DCD) ? 1 : 0; +} + +int tio_get_rs232_state(void) +{ + int flags; + + if( ioctl(0, TIOCMGET, &flags ) < 0 ) + return -1; + + DEB((D_MODEM, "tio_getrs232: [%s]-[%s]-[%s]-[%s]-[%s]-[%s]", + ( flags & TIO_RS232_RTS ) ? "RTS" : "rts", + ( flags & TIO_RS232_CTS ) ? "CTS" : "cts", + ( flags & TIO_RS232_DSR ) ? "DSR" : "dsr", + ( flags & TIO_RS232_DTR ) ? "DTR" : "dtr", + ( flags & TIO_RS232_DCD ) ? "DCD" : "dcd", + ( flags & TIO_RS232_RNG ) ? "RNG" : "rng")); + + return flags; +} + diff --git a/source/bforce/io_unix_tty.c b/source/bforce/io_unix_tty.c new file mode 100644 index 0000000..75224db --- /dev/null +++ b/source/bforce/io_unix_tty.c @@ -0,0 +1,438 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "io.h" + +#ifndef RX_BUFSIZE +#define RX_BUFSIZE 4096 +#endif +#ifndef TX_BUFSIZE +#define TX_BUFSIZE 4096 +#endif + +int tty_status = TTY_SUCCESS; +int tty_hangup = 0; +int tty_abort = 0; +int tty_online = 0; +int tty_modem = 0; + +static unsigned char rx_buf[RX_BUFSIZE]; +static unsigned char tx_buf[TX_BUFSIZE]; +static unsigned int rx_pos = 0; +static unsigned int tx_pos = 0; +static unsigned int rx_left = 0; /* Received bytes left */ +static unsigned int tx_left = TX_BUFSIZE; /* Free space left */ + +#ifdef MODEM_WATCH_CARRIER +# define CARRIER_CHECK() if( tty_modem && tty_online && !tty_hangup \ + && !tio_get_dcd(0) ) { \ + log("carrier lost"); tty_hangup = 1; } +#else +# define CARRIER_CHECK() +#endif + +const char *tty_errstr(int status) +{ + const char *msg; + + switch(status) { + case TTY_SUCCESS: msg = "No errors"; break; + case TTY_TIMEOUT: msg = "Time Out"; break; + case TTY_HANGUP: msg = "Hanged Up"; break; + case TTY_ERROR: msg = "IO Error"; break; + default: msg = "Unknown error"; break; + } + + return msg; +} + +/* + * On success, tty_select() return zero value and set/reset + * rd and wr to the appropriate values + */ +int tty_select(bool *rd, bool *wr, int timeout) +{ + fd_set rfds, wfds; + struct timeval tv; + int rc; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + if( rd ) { FD_SET(0,&rfds); *rd = FALSE; } + if( wr ) { FD_SET(1,&wfds); *wr = FALSE; } + tv.tv_sec = timeout; + tv.tv_usec = 0; + + CARRIER_CHECK(); + + if( (tty_online && tty_hangup) || tty_abort ) + { return( tty_status = TTY_HANGUP ); } + + rc = select(2, &rfds, &wfds, NULL, &tv); + + CARRIER_CHECK(); + + if( rc < 0 ) + { + if( errno == EINTR ) + if( (tty_online && tty_hangup) || tty_abort ) + { tty_status = TTY_HANGUP; } + else + { tty_status = TTY_SUCCESS; } + else + { tty_status = TTY_ERROR; } + } + else if( rc == 0 ) + { + tty_status = TTY_TIMEOUT; + } + else /* ( rc > 0 ) */ + { + tty_status = TTY_ERROR; + if( rd && FD_ISSET(0,&rfds) ) + { tty_status = TTY_SUCCESS; *rd = TRUE; } + if( wr && FD_ISSET(1,&wfds) ) + { tty_status = TTY_SUCCESS; *wr = TRUE; } + } + + DEB((D_TTYIO, "tty_select: return code = %s, rc = %d (rd=%s, wr=%s)", + tty_errstr(tty_status), rc, + rd ? *rd ? "true" : "false" : "null", + wr ? *wr ? "true" : "false" : "null")); + + return tty_status; +} + +/* + * It is a frontend to tty_select(), that also checks our program buffer + */ +int tty_xselect(bool *rd, bool *wr, int timeout) +{ + if( rd && rx_pos > 0 ) + { + (void)tty_select(NULL, wr, 0); *rd = TRUE; + return TTY_SUCCESS; + } + return tty_select(rd, wr, timeout); +} + +/* + * Return non-zero value if some data available for reading + * in input queue OR in our RX buffer + */ +int tty_charwait(int timeout) +{ + bool rd = FALSE; + + if( rx_pos > 0 ) + return 1; + else if( tty_select(&rd, NULL, timeout) == 0 && rd == TRUE ) + return 1; + else + return 0; +} + +/* + * On success return number of bytes received + */ +int tty_read(unsigned char *buf, size_t size) +{ + int rc; + + DEB((D_TTYIO, "tty_read: want read %d byte(s)", size)); + + CARRIER_CHECK(); + + if( (tty_online && tty_hangup) || tty_abort ) + { return( tty_status = TTY_HANGUP ); } + + rc = read(0, buf, size); + + CARRIER_CHECK(); + + if( (tty_online && tty_hangup) || tty_abort ) + { + tty_status = TTY_HANGUP; + } + else if( rc < 0 ) + { + if( errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK ) + { tty_status = TTY_TIMEOUT; } + else + { tty_status = TTY_ERROR; } + } + else /* ( rc >= 0 ) */ + tty_status = TTY_SUCCESS; + + DEB((D_TTYIO, "tty_read: return code = %s, rc = %d", + tty_errstr(tty_status), rc)); + + return tty_status == TTY_SUCCESS ? rc : tty_status; +} + +/* + * On success return number of bytes received + */ +int tty_read_timeout(unsigned char *buf, size_t size, int timeout) +{ + int rc; + bool rd = FALSE; + + tty_status = TTY_SUCCESS; + + DEB((D_TTYIO, "tty_read_timeout: want read %d byte(s), timeout = %d", size, timeout)); + + if( timeout > 0 ) + { + if( (rc = tty_select(&rd, NULL, timeout)) < 0 ) + return rc; + + if( rd ) + { + if( (rc = tty_read(buf, size)) == 0 ) + return TTY_ERROR; + + return rc; + } + + return TTY_TIMEOUT; + } + + return tty_read(buf, size); +} + +int tty_write(const unsigned char *buf, size_t size) +{ + int rc; + + DEB((D_TTYIO, "tty_write: want write %d byte(s)", size)); + + CARRIER_CHECK(); + + if( (tty_online && tty_hangup) || tty_abort ) + { return(tty_status = TTY_HANGUP); } + + rc = write(1, buf, size); + + CARRIER_CHECK(); + + if( rc < 0 ) + { + if( errno == EINTR ) + { + if( (tty_online && tty_hangup) || tty_abort ) + { tty_status = TTY_HANGUP; } + else + { tty_status = TTY_TIMEOUT; } + } + else if( errno == EAGAIN || errno == EWOULDBLOCK ) + { + tty_status = TTY_TIMEOUT; + } + else if( errno == EPIPE ) + { + tty_hangup = 1; + tty_status = TTY_HANGUP; + } + else + { + tty_status = TTY_ERROR; + } + } + else if( rc == 0 ) + tty_status = TTY_TIMEOUT; + else /* ( rc > 0 ) */ + tty_status = TTY_SUCCESS; + + DEB((D_TTYIO, "tty_write: return code = %s, rc = %d", + tty_errstr(tty_status), rc)); + + return (tty_status == TTY_SUCCESS) ? rc : tty_status; +} + +/* + * On success return number of bytes sent + */ +int tty_write_timeout(const unsigned char *buf, size_t size, int timeout) +{ + time_t timer; + int rc, pos = 0; + + DEB((D_TTYIO, "tty_write_timeout: want write %d byte(s), timeout = %d", size, timeout)); + + tty_status = TTY_SUCCESS; + timer_set(&timer, timeout); + + while( pos < size ) + { + if( timer_expired(timer) ) + { + break; + } + else if( (rc = tty_write(buf + pos, size - pos)) < 0 ) + { + if( rc == TTY_TIMEOUT ) + usleep(10000); /* 0.01 sec */ + else + return rc; + } + else /* ( rc > 0 ) */ + { + DEB((D_TTYIO, "tty_write_timeout: written %d byte(s)", rc)); + pos += rc; + } + } + + return (pos > 0) ? pos : TTY_TIMEOUT; +} + +int tty_putc(unsigned char ch, int timeout) +{ + return tty_write_timeout(&ch, 1, timeout); +} + +int tty_puts(const unsigned char *s, int timeout) +{ + return tty_write_timeout(s, strlen(s), timeout); +} + +int tty_getc(int timeout) +{ + int rc; + + tty_status = TTY_SUCCESS; + + if( rx_left == 0 ) + { + rx_pos = 0; + if( (rc = tty_read_timeout(rx_buf, sizeof(rx_buf), timeout)) < 0 ) + { + DEB((D_TTYIO, "tty_getc: tty_read() result \"%s\"", tty_errstr(rc))); + return rc; + } + else if( rc == 0 ) + return TTY_ERROR; /* Isn't it? */ + + rx_left = rc; + } + + rx_left--; + return rx_buf[rx_pos++]; +} + +int tty_bufc(unsigned char ch, int timeout) +{ + int rc; + + if( tx_left == 0 ) + { + if( (rc = tty_flushbuf(timeout)) < 0 ) return rc; + else if( rc == 0 ) return TTY_TIMEOUT; + } + + tx_buf[tx_pos++] = ch; + --tx_left; + + return(tty_status = TTY_SUCCESS); +} + +int tty_flushout(void) +{ + DEB((D_TTYIO, "tty_flushout: flushing out")); + + CARRIER_CHECK(); + + if( (tty_online && tty_hangup) || tty_abort ) + return(tty_status = TTY_HANGUP); + +#ifdef FUCKING_TCDRAIN + if( tty_modem ) + { + while( tcdrain(1) == -1 ) + { + if( errno == EINTR ) + { + if( (tty_online && tty_hangup) || tty_abort ) + return(tty_status = TTY_HANGUP); + } + else if( errno == EPIPE ) + return(tty_status = TTY_HANGUP); + else if( errno == EAGAIN || errno == EWOULDBLOCK ) + return(tty_status = TTY_SUCCESS); + else + return(tty_status = TTY_ERROR); + } + } +#endif /* FUCKING_TCDRAIN */ + + return(tty_status = TTY_SUCCESS); +} + +int tty_flushbuf(int timeout) +{ + int rc = 0; + + tty_status = TTY_SUCCESS; + + DEB((D_TTYIO, "tty_flushbuf: flushing internal TX buffer")); + + if( tx_pos ) + { + if( (rc = tty_write_timeout(tx_buf, tx_pos, timeout)) < 0 ) + { + return rc; + } + tx_pos -= rc; + tx_left += rc; + } + + return rc; +} + +int tty_clearin(void) +{ + DEB((D_TTYIO, "tty_clearin: clear RX buffers")); + + tcflush(0, TCIFLUSH); + + rx_left = 0; + rx_pos = 0; + + CARRIER_CHECK(); + + if( (tty_online && tty_hangup) || tty_abort ) + return(tty_status = TTY_HANGUP); + + return(tty_status = TTY_SUCCESS); +} + +int tty_clearout(void) +{ + DEB((D_TTYIO, "tty_clearout: clear TX buffers")); + + tcflush(1, TCOFLUSH); + + tx_left = TX_BUFSIZE; + tx_pos = 0; + + CARRIER_CHECK(); + + if( (tty_online && tty_hangup) || tty_abort ) + return(tty_status = TTY_HANGUP); + + return(tty_status = TTY_SUCCESS); +} diff --git a/source/bforce/logger.c b/source/bforce/logger.c new file mode 100644 index 0000000..9dd7fb7 --- /dev/null +++ b/source/bforce/logger.c @@ -0,0 +1,570 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "version.h" +#include "logger.h" +#include "util.h" + +/* + * Local variables for logger + */ +static FILE *log_fp = NULL; +static char log_name[BF_MAXPATH+1] = BFORCE_LOGFILE; +static char log_extension[32] = ""; +static char log_ident[32] = ""; +static char log_ttyname[32] = ""; + +#ifdef DEBUG +/* + * Local variables needed to make debug work + */ +static FILE *debug_fp = NULL; +static long debug_current_debuglevel = 0L; +static char debug_name[BF_MAXPATH+1] = BFORCE_DEBFILE; +static bool debug_invalid_name = FALSE; + +/* + * Debug level names + */ +struct debuglevel { + const char *keystr; + unsigned long value; +} debuglevels[] = { + { "Config", D_CONFIG }, + { "Override", D_OVERRIDE }, + { "Event", D_EVENT }, + { "Nodelist", D_NODELIST }, + { "Outbound", D_OUTBOUND }, + { "Info", D_INFO }, + { "HShake", D_HSHAKE }, + { "TtyIO", D_TTYIO }, + { "Modem", D_MODEM }, + { "Prot", D_PROT }, + { "Freq", D_FREQ }, + { "Statem", D_STATEM }, + { "Daemon", D_DAEMON }, + { "Full", D_FULL }, + { NULL, 0 } +}; +#endif /* DEBUG */ + +#ifdef USE_SYSLOG + +#include + +#endif /* ifdef USE_SYSLOG */ + +#ifndef USE_SYSLOG +const char *log_getfilename(int whatfor) +{ + const char *p = NULL; + + switch(whatfor) { + case LOG_FILE_DAEMON: + if( (p = conf_string(cf_log_file_daemon)) == NULL ) + p = DAEMON_LOGFILE; + break; + case LOG_FILE_SESSION: + if( (p = conf_string(cf_log_file)) == NULL ) + p = BFORCE_LOGFILE; + break; +#ifdef DEBUG + case LOG_FILE_DEBUG: + if( (p = conf_string(cf_debug_file)) == NULL ) + p = BFORCE_DEBFILE; + break; +#endif + case LOG_FILE_HISTORY: + break; + } + + return p; +} + +/* + * Logging part + */ +bool log_isopened(void) +{ + return log_fp ? TRUE : FALSE; +} + +int log_open(const char *logname, const char *ext, const char *tty) +{ + if( log_fp ) + log("warning: opening new log file, but previous was not closed"); + + if( logname ) + { + /* Reset previous settings */ + *log_name = '\0'; + *log_extension = '\0'; + *log_ttyname = '\0'; + + strnxcpy(log_name, logname, sizeof(log_name)); + + if( tty && *tty ) + strnxcpy(log_ttyname, tty, sizeof(log_ttyname)); + + if( ext && *ext ) + { + strnxcpy(log_extension, ext, sizeof(log_extension)); + strnxcat(log_name, ".", sizeof(log_name)); + strnxcat(log_name, ext, sizeof(log_name)); + } + + if( (log_fp = fopen(log_name, "a")) == NULL ) + { + logerr("can't open log file \"%s\"", log_name); + return -1; + } + } + else if( log_name ) + { + /* Open previously set log file */ + + if( (log_fp = fopen(log_name, "a")) == NULL ) + { + logerr("can't open log file \"%s\"", log_name); + return -1; + } + } else + return -1; + + return 0; +} + +int log_close(void) +{ + int rc = 0; + + ASSERT(log_fp); + + if( log_fp ) + { + rc = fclose(log_fp); log_fp = NULL; + } + + return rc; +} + +int log_reopen(const char *logname, const char *ext, const char *tty) +{ + ASSERT(logname != NULL); + + if( log_isopened() ) + { + if( !strcmp(logname, log_name) + && !strcmp(log_extension ? log_extension : "", ext ? ext : "") ) + { + return 0; + } + log_close(); + } + + return log_open(logname, ext, tty); +} + +/* void log_setident(const char *ident) +{ + if( ident ) + strnxcpy(log_ident, ident, sizeof(log_ident)); + else + *log_ident = '\0'; +} */ + +int log(const char *s, ...) + +{ + char timestr[40]; + va_list args; + + time_string_log(timestr, sizeof(timestr), 0); + + va_start(args, s); + + /* + * If log file is not opened print messages to the stderr + */ + if( log_fp == NULL ) + { + fprintf(stderr, "%s ", timestr); + vfprintf(stderr, s, args); + putc('\n', stderr); + fflush(stderr); + } + else + { + int mypid = getpid(); + + if( log_ident[0] && log_ttyname[0] ) + fprintf(log_fp, "%s %s.%s[%d] ", timestr, log_ident, log_ttyname, mypid); + else if( log_ident[0] ) + fprintf(log_fp, "%s %s[%d] ", timestr, log_ident, mypid); + else if( log_ttyname[0] ) + fprintf(log_fp, "%s %s[%d] ", timestr, log_ttyname, mypid); + else + fprintf(log_fp, "%s [%d] ", timestr, mypid); + + vfprintf(log_fp, s, args); + putc('\n', log_fp); + fflush(log_fp); + } + + va_end(args); + + return 0; +} + +int logerr(const char *s, ...) +{ + char timestr[40]; + va_list args; + + time_string_log(timestr, sizeof(timestr), 0); + + va_start(args, s); + + /* + * If log file is not opened print messages to the stderr + */ + if( log_fp == NULL ) + { + fprintf(stderr, "%s ", timestr); + vfprintf(stderr, s, args); + putc('\n', stderr); + + if( errno == EACCES ) + { + fprintf(stderr, "\tmessage: \"%s\" : errno = %d (euid = %d, egid = %d)\n", + strerror(errno), errno, geteuid(), getegid()); + } + else + { + fprintf(stderr, "\tmessage: \"%s\" : errno = %d\n", + strerror(errno), errno); + } + + fflush(stderr); + } + else + { + int mypid = getpid(); + + if( *log_ident && *log_ttyname ) + fprintf(log_fp, "%s %s.%s[%d] ", timestr, log_ident, log_ttyname, mypid); + else if( *log_ident ) + fprintf(log_fp, "%s %s[%d] ", timestr, log_ident, mypid); + else if( *log_ttyname ) + fprintf(log_fp, "%s %s[%d] ", timestr, log_ttyname, mypid); + else + fprintf(log_fp, "%s [%d] ", timestr, mypid); + + vfprintf(log_fp, s, args); + putc('\n', log_fp); + + /* + * Print error message according to the errno value + */ + if( errno == EACCES ) + { + fprintf(log_fp, "\tmessage: \"%s\" : errno = %d (euid = %d, egid = %d)\n", + strerror(errno), errno, geteuid(), getegid()); + } + else if( errno ) + { + fprintf(log_fp, "\tmessage: \"%s\" : errno = %d\n", + strerror(errno), errno); + } + + fflush(log_fp); + } + + va_end(args); + + return 0; +} + +#endif /* ifndef USE_SYSLOG */ + + +#ifdef USE_SYSLOG + +const char *log_getfilename(int whatfor) +{ + const char *p = "/dev/null"; + return p; +} + +bool log_isopened(void) +{ + return TRUE; +} + +int log_open(const char *logname, const char *ext, const char *tty) +{ + char *p = "bforce"; + int fac = conf_number(cf_syslog_facility); + if( tty && *tty ) + strncpy(p, tty, sizeof(p)); + openlog(p, LOG_PID, fac); + return 0; +} + +int log_reopen(const char *logname, const char *ext, const char *tty) +{ + return 0; +} + +int log_close(void) +{ + + closelog(); + return 0; + +} + +int log(const char *s, ...) + +{ + char timestr[40]; + va_list args; + + int fac = conf_number(cf_syslog_facility); + const int LP_TTY = fac || LOG_INFO; + const int LP_A = fac || LOG_NOTICE; + const int LP_O = fac || LOG_DEBUG; + const int log_priority = fac || LOG_ERR; + + time_string_log(timestr, sizeof(timestr), 0); + + va_start(args, s); + + int mypid = getpid(); + + if( log_ident[0] && log_ttyname[0] ) + syslog(LP_TTY, "%s %s.%s[%d] ", timestr, log_ident, log_ttyname, mypid); + else if( log_ident[0] ) + syslog(LP_A, "%s %s[%d] ", timestr, log_ident, mypid); + else if( log_ttyname[0] ) + syslog(LP_O, "%s %s[%d] ", timestr, log_ttyname, mypid); + else + fprintf(log_priority, "%s [%d] ", timestr, mypid); + + +/* vsyslog(log_priority, s, args);*/ +/* putc('\n', log_fp); + fflush(log_fp); + + } */ + + va_end(args); + + return 0; +} + +int logerr(const char *s, ...) + +{ + char timestr[40]; + va_list args; + + int fac = conf_number(cf_syslog_facility); + const int log_priority = fac || LOG_ERR; + + time_string_log(timestr, sizeof(timestr), 0); + + va_start(args, s); + + int mypid = getpid(); + +/* if( log_ident[0] && log_ttyname[0] ) + syslog(log_priority, "%s %s.%s[%d] ", timestr, log_ident, log_ttyname, mypid); + else if( log_ident[0] ) + syslog(log_priority, "%s %s[%d] ", timestr, log_ident, mypid); + else if( log_ttyname[0] ) + fprintf(log_priority, "%s %s[%d] ", timestr, log_ttyname, mypid); + else + fprintf(log_priority, "%s [%d] ", timestr, mypid); +*/ + + vsyslog(log_priority, s, args); +/* putc('\n', log_fp); + fflush(log_fp); + + } */ + + va_end(args); + + return 0; +} + +#endif /* ifdef USE_SYSLOG */ + + +/* + * Debugging part + */ + + +#ifdef DEBUG +void debug_setlevel(long newlevel, bool logit) +{ + if( logit && newlevel != debug_current_debuglevel ) + { + log("changing debug level from 0x%07x to 0x%07x", + debug_current_debuglevel, newlevel); + debug_current_debuglevel = newlevel; + } +} + +bool debug_isopened(void) +{ + return debug_fp ? TRUE : FALSE; +} + +int debug_parsestring(char *str, unsigned long *deblevel) +{ + int i, rc = 0; + char *n; + char *p_str = NULL; + + ASSERT(str != NULL); + + *deblevel = 0L; + + for( p_str = string_token(str, &n, NULL, 0); p_str; + p_str = string_token(NULL, &n, NULL, 0) ) + { + for( i = 0; debuglevels[i].keystr; i++ ) + { + if( strcasecmp(p_str, debuglevels[i].keystr) == 0 ) + { + *deblevel |= debuglevels[i].value; + break; + } + } + if( debuglevels[i].keystr == NULL ) + { + log("unknown debug level \"%s\"", p_str); + rc = 1; + } + } + return rc; +} + +void debug_setfilename(const char *debugname) +{ + ASSERT(debugname != NULL); + + if( !strcmp(debug_name, debugname) ) return; + + if( debug_isopened() ) debug_close(); + + /* Reset ignore flag */ + if( debug_invalid_name ) + debug_invalid_name = FALSE; + + strnxcpy(debug_name, debugname, sizeof(debug_name)); +} + +int debug_open(const char *debugname) +{ + char buf[40]; + + ASSERT(debug_fp == NULL); + + if( debugname ) + { + if( (debug_fp = fopen(debugname, "a")) == NULL ) + { + logerr("can't open debug file \"%s\"", debugname); + return -1; + } + strnxcpy(debug_name, debugname, sizeof(debug_name)); + } + else if( debug_name ) + { + if( (debug_fp = fopen(debug_name, "a")) == NULL ) + { + /* Don't try to open it next time */ + debug_invalid_name = TRUE; + + logerr("can't open debug file \"%s\"", debug_name); + return -1; + } + } else + return -1; + + /* Put banner */ + fprintf(debug_fp, "****************************************************\n"); + fprintf(debug_fp, " Starting binkleyforce version %s\n", BF_VERSION); + fprintf(debug_fp, " Time: %s, PID: %d, UID: %d, GID: %d, EUID: %d, EGID %d\n", + time_string_long(buf, sizeof(buf), 0), getpid(), + getuid(), getgid(), geteuid(), getegid()); + fprintf(debug_fp, "****************************************************\n"); + fflush(debug_fp); + + return 0; +} + +int debug_close(void) +{ + char buf[40]; + int rc = 0; + + ASSERT(debug_fp != NULL); + + if( debug_fp ) + { + fprintf(debug_fp, "****************************************************\n"); + fprintf(debug_fp, " Closing Binkley-Force debug file at %s\n", + time_string_long(buf, sizeof(buf), 0)); + fprintf(debug_fp, "****************************************************\n"); + + rc = fclose(debug_fp) ? 0 : -1; debug_fp = NULL; + } + + return rc; +} + +int debug(unsigned long what, const char *str, ...) +{ + char buf[40]; + va_list args; + + if( (what == 0 && debug_current_debuglevel) + || (debug_current_debuglevel & what) ) + { + if( debug_fp == NULL && debug_invalid_name == FALSE ) + { + debug_open(NULL); + } + + if( debug_fp ) + { + fprintf(debug_fp, "%s ", time_string_log(buf, sizeof(buf), 0)); + va_start(args, str); + vfprintf(debug_fp, str, args); + va_end(args); + putc('\n', debug_fp); + fflush(debug_fp); + } + } + + return 0; +} + +#endif /* DEBUG */ diff --git a/source/bforce/nodelist.c b/source/bforce/nodelist.c new file mode 100644 index 0000000..60dad93 --- /dev/null +++ b/source/bforce/nodelist.c @@ -0,0 +1,585 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" + +#define NODELIST_LOCK_TRIES 3 +#define NODELIST_LOCK_DELAY 1 /* seconds */ + +struct keyword { + const char *keystr; + const int keyval; +} keywords[] = { + { "", KEYWORD_EMPTY }, + { "Zone", KEYWORD_ZONE }, + { "Region", KEYWORD_REGION }, + { "Host", KEYWORD_HOST }, + { "Hub", KEYWORD_HUB }, + { "Pvt", KEYWORD_PVT }, + { "Hold", KEYWORD_HOLD }, + { "Down", KEYWORD_DOWN }, + { "Boss", KEYWORD_BOSS }, + { "Point", KEYWORD_POINT }, + { NULL, 0 } +}; + +/***************************************************************************** + * Check flag for existing in nodelist flags string + * + * Arguments: + * nodeflags pointer to the node's nodelist flags string + * flag pointer to the flag that we want to check + * + * Return value: + * zero value if flag is presented in flags, and non-zero if not + */ +int nodelist_checkflag(const char *nodeflags, const char *flag) +{ + char *p, *q; + + if( (p = strstr(nodeflags, flag)) ) + { + if( p == nodeflags || *(p-1) == ',' ) + { + if( (q = strchr(p, ',')) == NULL || (q - p) == strlen(flag) ) + return 0; + } + } + + return 1; +} + +/***************************************************************************** + * Get nodelist keyword (e.g. Host, Hub, Point, etc.) value + * (e.g. KEYWORD_HOST, KEYWORD_HUB, etc.) + * + * Arguments: + * keywordval pointer to the keyword string + * + * Return value: + * One of KEYWORD_* values, and -1 for unknown keywords + */ +int nodelist_keywordval(const char *keyword) +{ + int i; + + for( i = 0; keywords[i].keystr; i++ ) + { + if( strcmp(keyword, keywords[i].keystr) == 0 ) + { + return keywords[i].keyval; + } + } + return -1; +} + +int nodelist_parse_Txy(s_node *node, const char *xy) +{ + long beg; + long end; + long tz; + + if( xy[0] >= 'A' && xy[0] <= 'X' ) + beg = (xy[0] - 'A') * 60; + else if( xy[0] >= 'a' && xy[0] <= 'x' ) + beg = (xy[0] - 'a') * 60 + 30; + else + return -1; + + if( xy[1] >= 'A' && xy[1] <= 'X' ) + end = (xy[1] - 'A') * 60; + else if( xy[1] >= 'a' && xy[1] <= 'x' ) + end = (xy[1] - 'a') * 60 + 30; + else + return -1; + + if( beg == end ) + return -1; + + /* Convert it to local time */ + if( (tz = time_gmtoffset()) ) + { + beg -= tz; + if( beg > 1440 ) + beg = beg - 1440; + else if( beg < 0 ) + beg = beg + 1440; + else if( beg == 1440 ) + beg = 0; + + end -= tz; + if( end > 1440 ) + end = end - 1440; + else if( end < 0 ) + end = end + 1440; + else if( end == 1440 ) + end = 0; + } + + timevec_add(&node->worktime, DAY_MONDAY, DAY_SUNDAY, beg, end); + + return 0; +} + +/***************************************************************************** + * Nodelist string parser + * + * Arguments: + * node put here all obtained information + * str pointer to the nodelist string + * + * Return value: + * zero value if string was parsed successfuly, and non-zero if wasn't + */ +int nodelist_parsestring(s_node *node, char *str) +{ + char *argv[NODELIST_POSFLAGS+1]; + char *p; + + if( string_parse(argv, NODELIST_POSFLAGS+1, str, ',') != NODELIST_POSFLAGS+1 ) + return -1; + + if( !ISDEC(argv[NODELIST_POSNUMBER]) || !ISDEC(argv[NODELIST_POSSPEED]) ) + return -1; + if( (node->keyword = nodelist_keywordval(argv[NODELIST_POSKEYWORD])) == -1 ) + return -1; + + if( node->addr.zone ) + { + int number = atoi(argv[NODELIST_POSNUMBER]); + bool goodstr = FALSE; + + switch(node->keyword) { + case KEYWORD_ZONE: + goodstr = (node->addr.zone == number); + break; + case KEYWORD_REGION: + case KEYWORD_HOST: + goodstr = (node->addr.net == number); + break; + case KEYWORD_POINT: + goodstr = (node->addr.point == number); + break; + default: + goodstr = (node->addr.node == number); + break; + } + if( !goodstr ) return -1; + } + + strnxcpy(node->name, argv[NODELIST_POSNAME], sizeof(node->name)); + strnxcpy(node->location, argv[NODELIST_POSLOCATION], sizeof(node->location)); + strnxcpy(node->sysop, argv[NODELIST_POSSYSOP], sizeof(node->sysop)); + strnxcpy(node->phone, argv[NODELIST_POSPHONE], sizeof(node->phone)); + strnxcpy(node->flags, argv[NODELIST_POSFLAGS], sizeof(node->flags)); + node->speed = atoi(argv[NODELIST_POSSPEED]); + + /* + * Replace all '_' by space character + */ + string_replchar(node->name, '_', ' '); + string_replchar(node->location, '_', ' '); + string_replchar(node->sysop, '_', ' '); + + /* + * Get system work time (usefull flags: CM,Txy) + */ + if( nodelist_checkflag(node->flags, "CM") == 0 ) + { + timevec_add(&node->worktime, DAY_MONDAY, DAY_SUNDAY, 0, 1440); + } + else + { + for( p = node->flags; p && *p; p = strchr(p, ',') ) + { + if( p[1] == 'T' && p[2] && p[3] && (p[4] == ',' || p[4] == '\0') ) + { + if( nodelist_parse_Txy(node, p+2) == -1 ) + log("invalid nodelist Txy flag in \"%s\"", node->flags); + break; + } + p++; + } + + /* + * Set default work time according to ZMH + */ + if( node->addr.point == 0 ) + { + switch(node->addr.zone) { + case 1: nodelist_parse_Txy(node, "JK"); break; + case 2: nodelist_parse_Txy(node, "cd"); break; + case 3: nodelist_parse_Txy(node, "ST"); break; + case 4: nodelist_parse_Txy(node, "IJ"); break; + case 5: nodelist_parse_Txy(node, "BC"); break; + case 6: nodelist_parse_Txy(node, "UV"); break; + } + } + } + + return 0; +} + +/***************************************************************************** + * Open nodelist, nodelist index, do some checks + * + * Arguments: + * dir pointer to the nodelist's directory + * name pointer to the nodelist file name + * mode are we going to read nodelist index? Or write? + * + * Return value: + * pointer to the allocated nodelist structure (will be used with all + * nodelist operations), and NULL to indicate errors. + */ +s_nodelist *nodelist_open(const char *dir, const char *name, int mode) +{ + s_nodelist tmp; + const char *openmode; + int lockmode; + + memset(&tmp, '\0', sizeof(s_nodelist)); + + /* + * Select nodelist index open mode + */ + if( mode == NODELIST_READ ) + { + openmode = "r"; + lockmode = FILELOCK_READ; + } + else if( mode == NODELIST_WRITE ) + { + openmode = "w"; + lockmode = FILELOCK_WRITE; + } + else + ASSERT(0); + + /* + * Get nodelist and nodelist index file names + */ + if( *name == DIRSEPCHR ) + { + strnxcpy(tmp.name_nodelist, name, sizeof(tmp.name_nodelist)); + strnxcpy(tmp.name_index, name, sizeof(tmp.name_index)); + } + else + { + strnxcpy(tmp.name_nodelist, dir, sizeof(tmp.name_nodelist)); + strnxcat(tmp.name_nodelist, name, sizeof(tmp.name_nodelist)); + strnxcpy(tmp.name_index, tmp.name_nodelist, sizeof(tmp.name_index)); + } + strnxcat(tmp.name_index, ".index", sizeof(tmp.name_index)); + + DEB((D_NODELIST, "nodelist_open: nodelist name = \"%s\"", tmp.name_nodelist)); + DEB((D_NODELIST, "nodelist_open: nodelist index = \"%s\"", tmp.name_index)); + DEB((D_NODELIST, "nodelist_open: open mode = \"%s\"", openmode)); + + /* + * Try to open and lock nodelist + */ + if( (tmp.fp_nodelist = file_open(tmp.name_nodelist, "r")) == NULL ) + { + logerr("cannot open nodelist \"%s\"", tmp.name_nodelist); + return NULL; + } + + /* + * Try to open and lock nodelist index + */ + if( (tmp.fp_index = file_open(tmp.name_index, openmode)) == NULL ) + { + logerr("cannot open nodelist index \"%s\"", tmp.name_index); + fclose(tmp.fp_nodelist); + return NULL; + } + + /* + * If we open nodelist for reading then we should check that + * nodelist index has correct header and up to date + */ + if( mode == NODELIST_READ ) + { + if( nodelist_checkheader(&tmp) == -1 ) + { + file_close(tmp.fp_nodelist); + file_close(tmp.fp_index); + return NULL; + } + } + + return xmemcpy(&tmp, sizeof(s_nodelist)); +} + +/***************************************************************************** + * Check nodelist index header for valid nodelist date and size + * + * Arguments: + * nlp opened nodelist + * + * Return value: + * zero value if header is correct, and -1 if not + */ +int nodelist_checkheader(s_nodelist *nlp) +{ + unsigned long nltime; + unsigned long nlsize; + struct stat nlstat; + char buffer[NODELIST_HDRSIZE]; + + if( fread(buffer, sizeof(buffer), 1, nlp->fp_index) != 1 ) + { + logerr("cannot read header from nodelist index \"%s\"", nlp->name_index); + return -1; + } + + if( fstat(fileno(nlp->fp_nodelist), &nlstat) == -1 ) + { + logerr("cannot stat nodelist \"%s\"", nlp->name_nodelist); + return -1; + } + + nltime = buffer_getlong(buffer + 0); + nlsize = buffer_getlong(buffer + 4); + + if( (unsigned long)nlstat.st_mtime != nltime ) + { + log("invalid nodelist index: incorrect nodelist date %ld (expected %ld)", + (long)nlstat.st_mtime, (long)nltime); + return -1; + } + + if( (unsigned long)nlstat.st_size != nlsize ) + { + log("invalid nodelist index: incorrect nodelist size %ld (expected %ld)", + (long)nlstat.st_size, (long)nlsize); + return -1; + } + + return 0; +} + +/***************************************************************************** + * Create/update nodelist index header. Nodelist must be opened for + * writing. Now nodelist index header contain nodelist modification + * time and nodelist size. + * + * Arguments: + * nlp opened nodelist + * + * Return value: + * zero value on success, and -1 at errors + */ +int nodelist_createheader(s_nodelist *nlp) +{ + struct stat nlstat; + char hdrbuf[NODELIST_HDRSIZE]; + + memset(&hdrbuf, '\0', sizeof(hdrbuf)); + + if( fstat(fileno(nlp->fp_nodelist), &nlstat) == -1 ) + { + logerr("cannot stat nodelist \"%s\"", nlp->name_nodelist); + return -1; + } + + buffer_putlong(hdrbuf + 0, nlstat.st_mtime); + buffer_putlong(hdrbuf + 4, nlstat.st_size); + + if( fseek(nlp->fp_index, 0L, SEEK_SET) == -1 ) + { + logerr("cannot seek to zero offset of index"); + return -1; + } + + if( fwrite(hdrbuf, sizeof(hdrbuf), 1, nlp->fp_index) != 1 ) + { + logerr("cannot write nodelist index header"); + return -1; + } + + return 0; +} + +/***************************************************************************** + * Close nodelist and nodelist index files + * + * Arguments: + * nlp pointer to the opened nodelist + * + * Return value: + * Zero value if close was successful, and non-zero if not + */ +int nodelist_close(s_nodelist *nlp) +{ + int rc = 0; + + ASSERT(nlp && nlp->fp_nodelist && nlp->fp_index); + + if( nlp->fp_nodelist && file_close(nlp->fp_nodelist) ) + logerr("cannot close nodelist \"%s\"", nlp->name_nodelist); + + if( nlp->fp_index && file_close(nlp->fp_index) ) + { + logerr("cannot close nodelist index \"%s\"", nlp->name_index); + rc = 1; + } + + free(nlp); + + return rc; +} + +int nodelist_putindex(s_nodelist *nlp, const s_bni *bni) +{ + char buffer[NODELIST_ENTRYSIZE]; + + ASSERT(nlp && nlp->fp_index); + + buffer_putint(buffer + 0, bni->zone); + buffer_putint(buffer + 2, bni->net); + buffer_putint(buffer + 4, bni->node); + buffer_putint(buffer + 6, bni->point); + buffer_putint(buffer + 8, bni->hub); + buffer_putlong(buffer + 10, bni->offset); + + if( fwrite(buffer, sizeof(buffer), 1, nlp->fp_index) != 1 ) + { + logerr("error writing nodelist index file \"%s\"", nlp->name_index); + return -1; + } + + return 0; +} + +int nodelist_findindex(s_nodelist *nlp, s_bni *bni, s_faddr addr) +{ + long readitems; + char buffer[NODELIST_ENTRYSIZE * NODELIST_READAHEAD]; + char *p; + + if( fseek(nlp->fp_index, NODELIST_HDRSIZE, SEEK_SET) ) return -1; + + while(1) + { + if( (readitems = fread(buffer, NODELIST_ENTRYSIZE, NODELIST_READAHEAD, nlp->fp_index)) > 0 ) + { + for( p = buffer; readitems > 0; readitems-- ) + { + if( buffer_getint(p + 0) == addr.zone + && buffer_getint(p + 2) == addr.net + && buffer_getint(p + 4) == addr.node + && buffer_getint(p + 6) == addr.point ) + { + bni->zone = buffer_getint(p + 0); + bni->net = buffer_getint(p + 2); + bni->node = buffer_getint(p + 4); + bni->point = buffer_getint(p + 6); + bni->hub = buffer_getint(p + 8); + bni->offset = buffer_getlong(p + 10); + return 0; + } + p += NODELIST_ENTRYSIZE; + } + } else + return -1; + } + + return -1; +} + +int nodelist_getstr(s_nodelist *nlp, size_t offset, char *buffer, size_t buflen) +{ + ASSERT(nlp && nlp->fp_nodelist); + + if( fseek(nlp->fp_nodelist, offset, SEEK_SET) == 0 + && fgets(buffer, buflen, nlp->fp_nodelist) ) + { + string_chomp(buffer); + return 0; + } + + return -1; +} + +int nodelist_lookup_string(char *buffer, size_t buflen, s_faddr addr) +{ + s_bni bni; + s_cval_entry *ptrl; + s_nodelist *nlp; + const char *ndldir = NULL; + + ndldir = conf_string(cf_nodelist_directory); + + /* + * Try all nodelists with matching address mask + */ + for( ptrl = conf_first(cf_nodelist); ptrl; ptrl = conf_next(ptrl) ) + { + if( ftn_addrcomp_mask(addr, ptrl->d.falist.addr) == 0 ) + { + if( (nlp = nodelist_open(ndldir, ptrl->d.falist.what, NODELIST_READ)) ) + { + int rc = nodelist_findindex(nlp, &bni, addr); + + if( !rc ) + rc = nodelist_getstr(nlp, bni.offset, buffer, buflen); + + nodelist_close(nlp); + + if( !rc ) + return 0; + } + } + } + + return -1; +} + +int nodelist_lookup(s_node *node, s_faddr addr) +{ + char buf[512]; + char abuf[BF_MAXADDRSTR+1]; + + nodelist_initnode(node, addr); + + if( nodelist_lookup_string(buf, sizeof(buf), addr) == 0 ) + { + node->listed = TRUE; + if( nodelist_parsestring(node, buf) == -1 ) + { + log("invalid nodelist string for address %s", + ftn_addrstr(abuf, addr)); + } + return 0; + } + + return -1; +} + +void nodelist_initnode(s_node *node, s_faddr addr) +{ + memset(node, '\0', sizeof(s_node)); + + node->addr = addr; + strcpy(node->name, ""); + strcpy(node->sysop, ""); + strcpy(node->location, ""); + strcpy(node->phone, ""); +} + diff --git a/source/bforce/os_os2.c b/source/bforce/os_os2.c new file mode 100644 index 0000000..de48c25 --- /dev/null +++ b/source/bforce/os_os2.c @@ -0,0 +1,15 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" diff --git a/source/bforce/os_unix.c b/source/bforce/os_unix.c new file mode 100644 index 0000000..1651756 --- /dev/null +++ b/source/bforce/os_unix.c @@ -0,0 +1,469 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" + +struct { + char *name; + int value; +} exec_options_names[] = { + { "nowait", EXEC_OPT_NOWAIT }, + { "setsid", EXEC_OPT_SETSID }, + { "logout", EXEC_OPT_LOGOUT }, + { "useshell", EXEC_OPT_USESHELL }, + { NULL, 0 } +}; + +int exec_file_exist(const char *command) +{ + const char *p; + + ASSERT(command); + + if( *command == '[' ) + { + p = strchr(command + 1, ']'); + if( !p ) + return -1; + ++p; + } + else + p = command; + + if( !access(p, X_OK) ) + return 0; + + return -1; +} + +int exec_options_parse(char *str) +{ + int yield = 0; + char *p; + char *n; + int i; + + for( p = string_token(str, &n, ", \t", 0); p; + p = string_token(NULL, &n, ", \t", 0) ) + { + for( i = 0; exec_options_names[i].name; i++ ) + if( !strcasecmp(p, exec_options_names[i].name) ) + { + yield |= exec_options_names[i].value; + break; + } + if( !exec_options_names[i].name ) + log("unknown exec option '%s'", p); + } + + return yield; +} + +void exec_options_init(s_exec_options *eopt) +{ + memset(eopt, '\0', sizeof(s_exec_options)); + eopt->umask = EXEC_DEFAULT_UMASK; + eopt->envp[0] = NULL; +} + +void exec_options_deinit(s_exec_options *eopt) +{ + int i; + + if( eopt->command ) + free(eopt->command); + + for( i = 0; eopt->envp[i]; i++ ) + free(eopt->envp[i]); + + memset(eopt, '\0', sizeof(s_exec_options)); +} + +void exec_env_add(s_exec_options *eopt, const char *name, const char *value) +{ + int i; + + for( i = 0; eopt->envp[i]; i++ ); /* Empty Loop */ + + if( i < EXEC_MAX_NUM_ENVS ) + { + eopt->envp[i] = xmalloc(strlen(name) + strlen(value) + 2); + sprintf(eopt->envp[i], "%s=%s", name, value); + eopt->envp[i+1] = NULL; + } +} + +void exec_options_set_command(s_exec_options *eopt, const char *command) +{ + char *copy, *p; + + if( *command == '[' ) + { + copy = xstrcpy(command); + p = strchr(copy, ']'); + if( !p ) + eopt->command = copy; + else + { + *p++ = '\0'; + eopt->command = xstrcpy(string_trimleft(p)); + eopt->options = exec_options_parse(copy+1); + free(copy); + } + } + else + eopt->command = xstrcpy(command); +} + +int exec_redirect_descriptor(int desc, const char *fname, int flags) +{ + int fd; + + (void)close(desc); + + if( (fd = open(fname, flags, S_IRUSR|S_IWUSR)) == -1 ) + { + logerr("exec error: cannot open \"%s\"", fname); + return -1; + } + + if( fd != desc ) + { + log("exec error: cannot open \"%s\" <--> %d (got %d)", + fname, desc, fd); + return -1; + } + + return 0; +} + +int exec_command(s_exec_options *eopt) +{ + pid_t pid = 0; + int status = 0; + time_t starttime = 0; + time_t timer = 0; + char *tempfile = NULL; + struct sigaction new_chld; + struct sigaction old_chld; + sigset_t new_mask; + sigset_t old_mask; + + if( eopt->command == NULL ) + return -1; + + if( eopt->options & EXEC_OPT_LOGOUT ) + { + tempfile = file_gettmp(); + if( !tempfile ) + log("cannot generate temporary file name"); + } + + /* Block SIGCHLD */ + sigemptyset(&new_mask); + sigaddset(&new_mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &new_mask, NULL); + + /* Set the default SIGCHLD handler */ + new_chld.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &new_chld, &old_chld); + + if( (pid = fork()) == -1 ) + { + logerr("exec error: cannot fork()"); + return -1; + } + + if( !pid ) + { + if( exec_redirect_descriptor(0, "/dev/null", O_RDONLY) == -1 ) + exit(128); + + if( tempfile ) + { + if( exec_redirect_descriptor(1, tempfile, O_WRONLY|O_CREAT|O_TRUNC) == -1 + || exec_redirect_descriptor(2, tempfile, O_WRONLY) == -1 ) + exit(128); + } + else + { + if( exec_redirect_descriptor(1, "/dev/null", O_WRONLY) == -1 + || exec_redirect_descriptor(2, "/dev/null", O_WRONLY) == -1 ) + exit(128); + } + + if( eopt->options & EXEC_OPT_SETSID ) + setsid(); + + if( eopt->options & EXEC_OPT_USESHELL ) + execle("/bin/sh", "sh", "-c", eopt->command, NULL, eopt->envp); + else + { + char *argv[EXEC_MAX_NUM_ARGS+1]; + int argc = string_parse_regular(argv, EXEC_MAX_NUM_ARGS, + eopt->command); + if( argc > 0 ) + { + argv[argc] = NULL; + execve(argv[0], argv, eopt->envp); + } + /* eopt->command is corrupted now */ + } + + /* We get here only in case of errors */ + logerr("cannot execute \"%s\"", eopt->command); + + exit(128); + } + + /* + * We are inside parent process, do: + * + * 1) if OUTMODE_LOGPIPE is used than log child process ouput + * 2) wait for child process to exit + */ + + log("running \"%s\", PID %d", + string_printable(eopt->command), (int)pid); + + if( !(eopt->options & EXEC_OPT_NOWAIT) ) + { + starttime = time(NULL); /* Set process start time */ + + if( waitpid(pid, &status, 0) > 0 ) + { + eopt->runtime = time(NULL) - starttime; + + if( eopt->runtime < 0 ) + eopt->runtime = 0; + + /* + * Write process's output to the log file + */ + if( tempfile ) + { + char buf[256]; + FILE *fp = file_open(tempfile, "r"); + + if( !fp ) + logerr("cannot open temporary file \"%s\"", tempfile); + else + { + while( fgets(buf, sizeof(buf), fp) ) + { + string_chomp(buf); + log("[%d] %s", pid, string_printable(buf)); + } + file_close(fp); + } + } + + if( WIFEXITED(status) ) + { + eopt->retc = WEXITSTATUS(status); + log("process %d exit with code %d (%d seconds)", + (int)pid, eopt->retc, eopt->runtime); + } + else if( WIFSIGNALED(status) ) + { + eopt->retc = -1; + log("process %d terminated on signal %d (%d seconds)", + (int)pid, WTERMSIG(status), eopt->runtime); + } + else + { + eopt->retc = -1; + log("process %d return with unknown status (%d seconds)", + (int)pid, eopt->runtime); + } + } + else + { + eopt->retc = -1; + logerr("waitpid return error for PID %d", (int)pid); + } + } + + if( tempfile ) + { + if( unlink(tempfile) == -1 && errno != ENOENT ) + logerr("cannot unlink temporary file \"%s\"", tempfile); + free(tempfile); + } + + /* Restore the original SIGCHLD handler */ + sigaction(SIGCHLD, &old_chld, NULL); + + /* Unblock SIGCHLD */ + sigprocmask(SIG_UNBLOCK, &new_mask, NULL); + + return eopt->retc; +} + +/* + * Return -1 if error occured while excuting command, other values + * are return codes of your command + */ +int xsystem(const char *command, const char *p_input, const char *p_output) +{ + pid_t pid; + int status; + + ASSERT(command != NULL); + + DEB((D_INFO, "xsystem: command \"%s\", input \"%s\", output \"%s\"", + command, p_input, p_output)); + + switch(pid=fork()) { + case -1: + return(-1); + case 0: + if( p_input ) + { + close(0); + if( open(p_input, O_RDONLY) != 0 ) + { + logerr("can't open stdin \"%s\"", p_input); + exit(-1); + } + } + if( p_output ) + { + close(1); + if( open(p_output, O_WRONLY|O_APPEND|O_CREAT, 0600) != 1 ) + { + logerr("can't open stdout \"%s\"", p_output); + exit(-1); + } + } + if( p_output ) + { + close(2); + if( open(p_output, O_WRONLY|O_APPEND|O_CREAT, 0600) != 2 ) + { + logerr("can't open stderr \"%s\"", p_output); + exit(-1); + } + } +#ifdef SHELL + execl(SHELL, "sh", "-c", command, NULL); +#else + execl("/bin/sh", "sh", "-c", command, NULL); +#endif + exit( (errno == 0)?0:-1 ); + } + + if( waitpid(pid, &status, 0) == pid && WIFEXITED(status) ) + { + return(WEXITSTATUS(status)); + } + return(-1); +} + +#ifndef HAVE_RENAME +int rename(const char *old_name, const char *new_name) +{ + int rc; + + ASSERT(old_name != NULL && new_name != NULL); + + if( (rc = link(old_name, new_name)) == 0 ) + { + if( (rc = unlink(old_name)) == -1 ) + { logerr("can't unlink file \"%s\"", old_name); } + return 0; + } + else + { + return -1; + } +} +#endif + +/* ------------------------------------------------------------------------- */ +/* Get free space on device mounted at path $path */ +/* ------------------------------------------------------------------------- */ +#if defined(HAVE_STATFS) || defined(HAVE_STATVFS) +size_t getfreespace(const char *path) +{ +#ifdef HAVE_STATVFS + struct statvfs sfs; +#else + struct statfs sfs; +#endif + + ASSERT(path != NULL); + +#ifdef HAVE_STATVFS + if( statvfs(path, &sfs) == 0 ) +#else + if( statfs(path, &sfs) == 0 ) +#endif + { + return(sfs.f_bsize * sfs.f_bavail); + } + else + { + logerr("can't statfs \"%s\", assume enough space", path); + return(~0L); + } +} +#else +size_t getfreespace(const char *path) +{ + ASSERT(path != NULL); + + log("warning: fake getfreespace - assume enough space"); + return(~0L); +} +#endif + +#ifndef HAVE_SETPROCTITLE + +/* + * clobber argv so ps will show what we're doing. + * (stolen from BSD ftpd where it was stolen from sendmail) + * warning, since this is usually started from inetd.conf, it + * often doesn't have much of an environment or arglist to overwrite. + */ + +static char *cmdstr = NULL; +static char *cmdstrend = NULL; + +void setargspace(char *argv[], char *envp[]) +{ + cmdstr = argv[0]; + while( *envp ) envp++; + envp--; + cmdstrend = (*envp) + strlen(*envp); +} + +void setproctitle(const char *fmt, ...) +{ + va_list args; + char buf[256]; /* I hope it will be large enough */ + char *d = cmdstr; + char *s = buf; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + + /* Make ps print our process name */ + while( d < cmdstrend && *s ) { *d = *s; d++; s++; } + while( d < cmdstrend ) *d++ = ' '; +} + +#endif /* HAVE_SETPROCTITLE */ diff --git a/source/bforce/os_w32.c b/source/bforce/os_w32.c new file mode 100644 index 0000000..de48c25 --- /dev/null +++ b/source/bforce/os_w32.c @@ -0,0 +1,15 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" diff --git a/source/bforce/outb_bsy.c b/source/bforce/outb_bsy.c new file mode 100644 index 0000000..1495e42 --- /dev/null +++ b/source/bforce/outb_bsy.c @@ -0,0 +1,424 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "outbound.h" + +typedef struct bsylist { + s_faddr addr; + char *name_4d; + char *name_domain; + char *name_amiga; + struct bsylist *next; +#ifdef BFORCE_USE_CSY + bool is_csy; +#endif +} s_bsylist; + +s_bsylist *bsylist = NULL; + +static int out_bsy_convert_csy_to_bsy(s_bsylist *ptrl); + +/* ========================================================================= */ +/* PRIVATE part */ +/* ========================================================================= */ + +static int out_bsy_file_check(const char *name, const char *ext) +{ + char lockname[BFORCE_MAX_PATH+1]; + + ASSERT(name != NULL && ext != NULL); + + strnxcpy(lockname, name, sizeof(lockname)); + strnxcat(lockname, ext, sizeof(lockname)); + + return plock_check(lockname); +} + +static int out_bsy_file_create(const char *name, const char *ext) +{ + char lockname[BFORCE_MAX_PATH+1]; + + ASSERT(name != NULL && ext != NULL); + + strnxcpy(lockname, name, sizeof(lockname)); + strnxcat(lockname, ext, sizeof(lockname)); + + return plock_create(lockname); +} + +static int out_bsy_file_link(const char *oldname, const char *oldext, + const char *newname, const char *newext) +{ + char old_lockname[BFORCE_MAX_PATH+1]; + char new_lockname[BFORCE_MAX_PATH+1]; + + ASSERT(oldname != NULL && oldext != NULL); + ASSERT(newname != NULL && newext != NULL); + + strnxcpy(old_lockname, oldname, sizeof(old_lockname)); + strnxcat(old_lockname, oldext, sizeof(old_lockname)); + strnxcpy(new_lockname, newname, sizeof(new_lockname)); + strnxcat(new_lockname, newext, sizeof(new_lockname)); + + return plock_link(new_lockname, old_lockname); +} + +static int out_bsy_file_unlink(const char *name, const char *ext) +{ + char lockname[BFORCE_MAX_PATH+1]; + + ASSERT(name != NULL && ext != NULL); + + strnxcpy(lockname, name, sizeof(lockname)); + strnxcat(lockname, ext, sizeof(lockname)); + + return plock_remove(lockname); +} + +/* ========================================================================= */ +/* PUBLIC part */ +/* ========================================================================= */ + +int out_bsy_check(s_faddr addr) +{ + bool isfailed = FALSE; + char *name_4d = NULL; + char *name_domain = NULL; + char *name_amiga = NULL; + + name_4d = out_getname_4d(addr); + name_domain = out_getname_domain(addr); + name_amiga = out_getname_amiga(addr); + + DEB((D_OUTBOUND, "out_bsy_check: name_4d = \"%s\"", name_4d)); + DEB((D_OUTBOUND, "out_bsy_check: name_domain = \"%s\"", name_domain)); + DEB((D_OUTBOUND, "out_bsy_check: name_amiga = \"%s\"", name_amiga)); + + /* Check for BSY files in all outbounds */ + if( (name_4d && out_bsy_file_check(name_4d, ".bsy") == PLOCK_EXIST) + || (name_domain && out_bsy_file_check(name_domain, ".bsy") == PLOCK_EXIST) + || (name_amiga && out_bsy_file_check(name_amiga, ".bsy") == PLOCK_EXIST) ) + isfailed = TRUE; + +#ifdef BFORCE_USE_CSY + if( !isfailed ) + { + /* Check for CSY files in all outbounds */ + if( (name_4d && out_bsy_file_check(name_4d, ".csy") == PLOCK_EXIST) + || (name_domain && out_bsy_file_check(name_domain, ".csy") == PLOCK_EXIST) + || (name_amiga && out_bsy_file_check(name_amiga, ".csy") == PLOCK_EXIST) ) + isfailed = TRUE; + } +#endif + + if( name_4d ) + free(name_4d); + if( name_domain ) + free(name_domain); + if( name_amiga ) + free(name_amiga); + + return isfailed ? -1 : 0; +} + +#ifdef BFORCE_USE_CSY +int out_bsy_lock(s_faddr addr, bool csy_locks) +#else +int out_bsy_lock(s_faddr addr) +#endif +{ + char *name_4d = NULL; + char *name_domain = NULL; + char *name_amiga = NULL; + bool locked_4d = FALSE; + bool locked_domain = FALSE; + bool locked_amiga = FALSE; + s_bsylist bsytmp, **bsylst; + bool isfailed = FALSE; +#ifdef DEBUG + char abuf[BF_MAXADDRSTR+1]; +#endif +#ifdef BFORCE_USE_CSY + const char *lockext = csy_locks ? ".csy" : ".bsy"; +#else + const char *lockext = ".bsy"; +#endif + + DEB((D_OUTBOUND, "out_bsy_lock: lock address %s", + ftn_addrstr(abuf, addr))); + + /* + * Check, may be we've allready locked this address. + */ + for( bsylst = &bsylist; *bsylst; bsylst = &(*bsylst)->next ) + { + if( !ftn_addrcomp((*bsylst)->addr, addr) ) + { + DEB((D_OUTBOUND, "out_bsy_lock: address is allready locked")); +#ifdef BFORCE_USE_CSY + if( (*bsylst)->is_csy && !csy_locks ) + return out_bsy_convert_csy_to_bsy(*bsylst); +#else + return 0; +#endif + } + } + + name_4d = out_getname_4d(addr); + name_domain = out_getname_domain(addr); + name_amiga = out_getname_amiga(addr); + + DEB((D_OUTBOUND, "out_bsy_lock: name_4d = \"%s\"", name_4d)); + DEB((D_OUTBOUND, "out_bsy_lock: name_domain = \"%s\"", name_domain)); + DEB((D_OUTBOUND, "out_bsy_lock: name_amiga = \"%s\"", name_amiga)); + + /* Check for BSY files in all outbounds */ + if( (name_4d && out_bsy_file_check(name_4d, ".bsy") == PLOCK_EXIST) + || (name_domain && out_bsy_file_check(name_domain, ".bsy") == PLOCK_EXIST) + || (name_amiga && out_bsy_file_check(name_amiga, ".bsy") == PLOCK_EXIST) ) + isfailed = TRUE; + +#ifdef BFORCE_USE_CSY + if( !isfailed ) + { + /* Check for CSY files in all outbounds */ + if( (name_4d && out_bsy_file_check(name_4d, ".csy") == PLOCK_EXIST) + || (name_domain && out_bsy_file_check(name_domain, ".csy") == PLOCK_EXIST) + || (name_amiga && out_bsy_file_check(name_amiga, ".csy") == PLOCK_EXIST) ) + isfailed = TRUE; + } +#endif + + DEB((D_OUTBOUND, "out_bsy_lock: lock check result: %s", + isfailed ? "Locked" : "Not locked")); + + /* Create ?SY file in 4D outbound */ + if( !isfailed && name_4d ) + { + switch( out_bsy_file_create(name_4d, lockext) ) { + case PLOCK_OK: locked_4d = TRUE; break; + case PLOCK_EXIST: isfailed = TRUE; break; + case PLOCK_ERROR: locked_4d = FALSE; break; + } + } + + /* Create ?SY file in domain outbound */ + if( !isfailed && name_domain ) + { + switch( out_bsy_file_create(name_domain, lockext) ) { + case PLOCK_OK: locked_domain = TRUE; break; + case PLOCK_EXIST: isfailed = TRUE; break; + case PLOCK_ERROR: locked_domain = FALSE; break; + } + } + + /* Create ?SY file in "AmigaDos" outbound */ + if( !isfailed && name_amiga ) + { + switch( out_bsy_file_create(name_amiga, lockext) ) { + case PLOCK_OK: locked_amiga = TRUE; break; + case PLOCK_EXIST: isfailed = TRUE; break; + case PLOCK_ERROR: locked_amiga = FALSE; break; + } + } + +#ifdef BFORCE_USE_CSY + if( !isfailed ) + { + /* Check for BSY files in all outbounds */ + if( (name_4d && out_bsy_file_check(name_4d, ".bsy") == PLOCK_EXIST) + || (name_domain && out_bsy_file_check(name_domain, ".bsy") == PLOCK_EXIST) + || (name_amiga && out_bsy_file_check(name_amiga, ".bsy") == PLOCK_EXIST) ) + isfailed = TRUE; + } +#endif + + DEB((D_OUTBOUND, "out_bsy_lock: lock create result: %s", + isfailed ? "Failed" : "Successful")); + + /* Somebody else create BSY before us?! */ + if( isfailed ) + { + if( locked_4d ) + out_bsy_file_unlink(name_4d, lockext); + if( locked_domain ) + out_bsy_file_unlink(name_domain, lockext); + if( locked_amiga ) + out_bsy_file_unlink(name_amiga, lockext); + + if( name_4d ) + free(name_4d); + if( name_domain ) + free(name_domain); + if( name_amiga ) + free(name_amiga); + + return -1; + } + + /* + * Successful locking. Add new entry to the ``bsylist''. + */ + + memset(&bsytmp, '\0', sizeof(s_bsylist)); + + bsytmp.addr = addr; + +#ifdef BFORCE_USE_CSY + bsytmp.is_csy = csy_locks; +#endif + + if( locked_4d ) + bsytmp.name_4d = name_4d; + if( locked_domain ) + bsytmp.name_domain = name_domain; + if( locked_amiga ) + bsytmp.name_amiga = name_amiga; + + for( bsylst = &bsylist; *bsylst; bsylst = &(*bsylst)->next ) + { + /* EMPTY LOOP */ + } + + (*bsylst) = (s_bsylist*)xmalloc(sizeof(s_bsylist)); + **bsylst = bsytmp; + + return 0; +} + +int out_bsy_unlockall(void) +{ + s_bsylist *ptrl, *next; +#ifdef DEBUG + char abuf[BFORCE_MAX_ADDRSTR+1]; +#endif + + for( ptrl = bsylist; ptrl; ptrl = next ) + { +#ifdef BFORCE_USE_CSY + const char *lockext = ptrl->is_csy ? ".csy" : ".bsy"; +#else + const char *lockext = ".bsy"; +#endif + next = ptrl->next; + + DEB((D_OUTBOUND, "out_bsy_unlockall: unlock address %s", + ftn_addrstr(abuf, ptrl->addr))); + + if( ptrl->name_4d ) + { + out_bsy_file_unlink(ptrl->name_4d, lockext); + free(ptrl->name_4d); + } + + if( ptrl->name_domain ) + { + out_bsy_file_unlink(ptrl->name_domain, lockext); + free(ptrl->name_domain); + } + + if( ptrl->name_amiga ) + { + out_bsy_file_unlink(ptrl->name_amiga, lockext); + free(ptrl->name_amiga); + } + + free(ptrl); + } + + bsylist = NULL; + + return 0; +} + +#ifdef BFORCE_USE_CSY +static int out_bsy_convert_csy_to_bsy(s_bsylist *ptrl) +{ + bool locked_4d = FALSE; + bool locked_domain = FALSE; + bool locked_amiga = FALSE; + bool isfailed = FALSE; +#ifdef DEBUG + char abuf[BF_MAXADDRSTR+1]; +#endif + + DEB((D_OUTBOUND, "out_bsy_convert_csy_to_bsy: process address %s", + ftn_addrstr(abuf, ptrl->addr))); + + if( !ptrl->is_csy ) + { + DEB((D_OUTBOUND, "out_bsy_convert_csy_to_bsy: skip (no csy locks)")); + return 0; + } + +#define LINK_CSY_TO_BSY(lockname) \ + out_bsy_file_link(lockname, ".csy", lockname, ".bsy") + + /* Create BSY file in 4D outbound */ + if( !isfailed && ptrl->name_4d ) + { + switch( LINK_CSY_TO_BSY(ptrl->name_4d) ) { + case PLOCK_OK: locked_4d = TRUE; break; + case PLOCK_EXIST: isfailed = TRUE; break; + case PLOCK_ERROR: locked_4d = FALSE; break; + } + } + + /* Create BSY file in domain outbound */ + if( !isfailed && ptrl->name_domain ) + { + switch( LINK_CSY_TO_BSY(ptrl->name_domain) ) { + case PLOCK_OK: locked_domain = TRUE; break; + case PLOCK_EXIST: isfailed = TRUE; break; + case PLOCK_ERROR: locked_domain = FALSE; break; + } + } + + /* Create BSY file in "AmigaDos" outbound */ + if( !isfailed && ptrl->name_amiga ) + { + switch( LINK_CSY_TO_BSY(ptrl->name_amiga) ) { + case PLOCK_OK: locked_amiga = TRUE; break; + case PLOCK_EXIST: isfailed = TRUE; break; + case PLOCK_ERROR: locked_amiga = FALSE; break; + } + } + + DEB((D_OUTBOUND, "out_csy_to_bsy: lock create result: %s", + isfailed ? "Failed" : "Successful")); + + /* Somebody else create BSY before us?! */ + if( isfailed ) + { + if( locked_4d ) + out_bsy_file_unlink(ptrl->name_4d, ".bsy"); + if( locked_domain ) + out_bsy_file_unlink(ptrl->name_domain, ".bsy"); + if( locked_amiga ) + out_bsy_file_unlink(ptrl->name_amiga, ".bsy"); + + /* Leave ``.csy'' files untouched! */ + + return 1; + } + + ptrl->is_csy = FALSE; + + return 0; +} +#endif /* BFORCE_USE_CSY */ + diff --git a/source/bforce/outb_flo.c b/source/bforce/outb_flo.c new file mode 100644 index 0000000..bd6ebdc --- /dev/null +++ b/source/bforce/outb_flo.c @@ -0,0 +1,228 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "outbound.h" + +char *flo_translate(char *buffer, size_t buflen) +{ + char *p; + s_cval_entry *ptrl; + + ASSERT(buffer && buflen); + + for( ptrl = conf_first(cf_flo_translate); ptrl; + ptrl = conf_next(ptrl) ) + { + ASSERT(ptrl->d.translate.find); + + if( (p = strstr(buffer, ptrl->d.translate.find)) ) + { + char *new = string_translate(buffer, + ptrl->d.translate.find, + ptrl->d.translate.repl); + if( new ) + { + strnxcpy(buffer, new, buflen); + free(new); + } +/* + * I don't want to test it + */ +#ifdef XXX + int find_len = strlen(ptrl->d.translate.find); + + if( ptrl->d.translate.repl ) + { + int repl_len = strlen(ptrl->d.translate.repl); + if( repl_len < find_len ) + { + memcpy(p, ptrl->d.translate.repl, repl_len); + memmove(p+repl_len, p+find_len, strlen(p+find_len)+1); + } + else if( repl_len == find_len ) + { + memcpy(p, ptrl->d.translate.repl, repl_len); + } + else /* ( repl_len > find_len ) */ + { + /* TODO =) */ + } + } + else + memmove(p, p+find_len, strlen(p+find_len)+1); +#endif /* XXX */ + } + } + + return buffer; +} + +s_FLO *flo_open(const char *path, const char *mode) +{ + FILE *fp; + s_FLO *FLO; + + if( (fp = file_open(path, mode)) == NULL ) + return NULL; + + FLO = (s_FLO *)xmalloc(sizeof(s_FLO)); + memset(FLO, 0, sizeof(s_FLO)); + FLO->fp = fp; + + return FLO; +} + +int flo_next(s_FLO *FLO) +{ +restart: + FLO->att_offs = ftell(FLO->fp); + if( FLO->att_offs == -1 ) + return -1; + + if( fgets(FLO->att_path, BFORCE_MAX_PATH, FLO->fp) == NULL ) + return -1; + + if( string_is_empty(FLO->att_path) || *FLO->att_path == '~' ) + goto restart; + + string_chomp(FLO->att_path); + + switch(*FLO->att_path) { + case '@': + FLO->att_action = ACTION_NOTHING; + memmove(FLO->att_path, FLO->att_path+1, strlen(FLO->att_path+1)+1); + break; + case '^': + case '-': + FLO->att_action = ACTION_UNLINK; + memmove(FLO->att_path, FLO->att_path+1, strlen(FLO->att_path+1)+1); + break; + case '#': + FLO->att_action = ACTION_TRUNCATE; + memmove(FLO->att_path, FLO->att_path+1, strlen(FLO->att_path+1)+1); + break; + default: + FLO->att_action = ACTION_NOTHING; + } + + flo_translate(FLO->att_path, BFORCE_MAX_PATH); + + return 0; +} + +int flo_mark_sent(s_FLO *FLO) +{ + long myoffs = ftell(FLO->fp); + + if( fseek(FLO->fp, (long)FLO->att_offs, SEEK_SET) == -1 + || fputc('~', FLO->fp) == EOF ) + return -1; + + if( myoffs >= 0 ) + fseek(FLO->fp, myoffs, SEEK_SET); + + return 0; +} + +int flo_eof(s_FLO *FLO) +{ + return feof(FLO->fp); +} + +int flo_close(s_FLO *FLO) +{ + int rc = file_close(FLO->fp); + free(FLO); + return rc; +} +/* + * Return "TRUE" if no more files to send left in the FLO + */ +bool out_flo_isempty(const char *path) +{ + bool rc; + s_FLO *FLO; + + if( (FLO = flo_open(path, "r")) == NULL ) + return FALSE; + + while( flo_next(FLO) == 0 ) + { + if( access(FLO->att_path, F_OK) == 0 ) + return FALSE; + } + rc = flo_eof(FLO) ? TRUE : FALSE; + + flo_close(FLO); + + return rc; +} + +/* + * Mark the file name in FLO file as sent ( with '~' prefix ) + */ +int out_flo_marksent(const char *fname, const char *floname) +{ + int rc = -1; + s_FLO *FLO; + + if( (FLO = flo_open(floname, "r+")) == NULL ) + { + logerr("can't open flo file \"%s\"", floname); + return -1; + } + + while( flo_next(FLO) == 0 ) + { + if( strcmp(fname, FLO->att_path) == 0 ) + { + if( flo_mark_sent(FLO) == -1 ) + logerr("can't mark \"%s\" as sent in \"%s\"", + fname, floname); + else + rc = 0; + break; + } + } + + if( rc == -1 && flo_eof(FLO) ) + rc = 0; + + flo_close(FLO); + + return rc; +} + +/* + * Unlink empty .?lo files + */ +int out_flo_unlinkempty(const s_flofile *flotab, int flonum) +{ + int i; + + for( i = 0; i < flonum; i++ ) + { + if( out_flo_isempty(flotab[i].fname) ) + { + if( unlink(flotab[i].fname) == -1 ) + logerr("cannot unlink empty flo file \"%s\"", + flotab[i].fname); + } + } + + return 0; +} diff --git a/source/bforce/outb_fsqueue.c b/source/bforce/outb_fsqueue.c new file mode 100644 index 0000000..ddf0e9f --- /dev/null +++ b/source/bforce/outb_fsqueue.c @@ -0,0 +1,255 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "outbound.h" + +int out_filetype(const char *fname) +{ + const char *p_nam; + const char *p_ext; + int i; + + /* + * Get only file name, w/o dir part + */ + if( (p_nam = strrchr(fname, DIRSEPCHR)) ) + p_nam++; + else + p_nam = fname; + + /* + * Get file name extension + */ + if( (p_ext = strrchr(p_nam, '.')) == NULL ) + return TYPE_UNKNOWN; + + for( i = 0; outtab[i].ext; i++ ) + if( strcasemask(p_ext, outtab[i].ext) == 0 ) + return outtab[i].type; + + for( i = 0; exttab[i].ext; i++ ) + if( strcasemask(p_ext, exttab[i].ext) == 0 ) + return exttab[i].type; + + return TYPE_UNKNOWN; +} + +/* ------------------------------------------------------------------------- */ +/* Read FLO file line by line and call handler proc for each file in FLO */ +/* ------------------------------------------------------------------------- */ +static int out_readflo(s_filelist **fslist, const char *floname, + int flavor, bool aso, int flodsc) +{ + s_FLO *FLO; + s_filelist **tmpl; + struct stat st; + int type; + + DEB((D_OUTBOUND, "out_readflo: opening flo file \"%s\"", floname)); + + if( (FLO = flo_open(floname, "r")) == NULL ) + { + logerr("can't open flo \"%s\"", floname); + return -1; + } + + for( tmpl = fslist; *tmpl; tmpl = &(*tmpl)->next ); + + while( flo_next(FLO) == 0 ) + { + if( stat(FLO->att_path, &st) == 0 ) + { + type = out_filetype(FLO->att_path); + type |= TYPE_FROMFLO; + type |= aso ? TYPE_ASONAME : 0; + + (*tmpl) = (s_filelist*)xmalloc(sizeof(s_filelist)); + memset(*tmpl, '\0', sizeof(s_filelist)); + (*tmpl)->fname = (char *)xstrcpy(FLO->att_path); + (*tmpl)->size = st.st_size; + (*tmpl)->type = type; + (*tmpl)->flavor = flavor; + (*tmpl)->action = FLO->att_action; + (*tmpl)->status = STATUS_WILLSEND; + (*tmpl)->flodsc = flodsc; + tmpl = &(*tmpl)->next; + } + else + logerr("can't stat file \"%s\" from flo \"%s\"", + FLO->att_path, floname); + } + + flo_close(FLO); + return 0; +} + +/* + * Add new entry to the flo files table, return it's index number + */ +static int out_addfloentry(s_fsqueue *q, const char *floname, int flavor) +{ + q->flotab = (s_flofile*)xrealloc(q->flotab, sizeof(s_flofile)*(q->flonum+1)); + + memset(&q->flotab[q->flonum], '\0', sizeof(s_flofile)); + q->flotab[q->flonum].fname = xstrcpy(floname); + q->flotab[q->flonum].flavor = flavor; + q->flonum++; + + return q->flonum-1; +} + +/* ------------------------------------------------------------------------- */ +/* Handle each file $fi found in outbound. Usually it called by outbound */ +/* scanner.. Pointer to result information will be stored at dst */ +/* ------------------------------------------------------------------------- */ +int out_handle_fsqueue(s_outbound_callback_data *callback) +{ + s_fsqueue *queue; + int type; + int flavor; + int action; + + ASSERT(callback); + ASSERT(callback->path); + ASSERT(callback->dest); + + queue = (s_fsqueue*)callback->dest; + + DEB((D_OUTBOUND, "out_handle_fsqueue: process file \"%s\"", + callback->path)); + + if( callback->type != OUTB_TYPE_FBOX ) + { + int i; + const char *p_ext = strrchr(callback->path, '.'); + + if( !p_ext ) + return -1; + + for( i = 0; outtab[i].ext && strcasecmp(p_ext, outtab[i].ext); i++ ); + if( !outtab[i].ext ) + return -1; + + type = outtab[i].type; + flavor = outtab[i].flavor; + action = outtab[i].action; + } + else + { + type = out_filetype(callback->path) | TYPE_FILEBOX; + if( callback->flavor != -1 ) + flavor = callback->flavor; + else + flavor = FLAVOR_HOLD; + action = ACTION_UNLINK; + } + + if( (type & TYPE_NETMAIL) == TYPE_NETMAIL + || (type & TYPE_REQUEST) == TYPE_REQUEST + || (type & TYPE_FILEBOX) == TYPE_FILEBOX ) + { + struct stat st; + if( stat(callback->path, &st) == 0 ) + { + s_filelist **tmpl; + for( tmpl = &queue->fslist; *tmpl; tmpl = &(*tmpl)->next ); + (*tmpl) = (s_filelist*)xmalloc(sizeof(s_filelist)); + memset(*tmpl, '\0', sizeof(s_filelist)); + (*tmpl)->fname = xstrcpy(callback->path); + (*tmpl)->size = st.st_size; + (*tmpl)->type = type | + (callback->type == OUTB_TYPE_ASO ? TYPE_ASONAME : 0); + (*tmpl)->flavor = flavor; + (*tmpl)->action = action; + (*tmpl)->status = STATUS_WILLSEND; + (*tmpl)->flodsc = -1; + } + else + logerr("can't stat file \"%s\"", callback->path); + } + else if( (type & TYPE_FLOFILE) == TYPE_FLOFILE ) + { + out_readflo(&queue->fslist, callback->path, + flavor, (callback->type == OUTB_TYPE_ASO), + out_addfloentry(queue, callback->path, flavor)); + } + + return 0; +} + +void deinit_filelist(s_filelist *filelist) +{ + struct filelist *ptrl, *next; + + for( ptrl = filelist; ptrl; ptrl = next ) + { + next = ptrl->next; + if( ptrl->fname ) free(ptrl->fname); + free(ptrl); + } +} + +void deinit_fsqueue(s_fsqueue *q) +{ + int i; + + if( q->fslist ) + deinit_filelist(q->fslist); + + if( q->flotab ) + { + for( i = 0; i < q->flonum; i++ ) + if( q->flotab[i].fname ) free(q->flotab[i].fname); + free(q->flotab); + } + + memset(q, '\0', sizeof(s_fsqueue)); +} + +#ifdef DEBUG +void log_filelist(const s_filelist *filelist) +{ + const s_filelist *ptrl; + + DEB((D_OUTBOUND, "log_filelist: BEGIN")); + for( ptrl = filelist; ptrl; ptrl = ptrl->next ) + { + DEB((D_OUTBOUND, "log_filelist: \tfile \"%s\", %ld byte(s), flodsc = %d, status: \"%s\"", + ptrl->fname, (long)ptrl->size, ptrl->flodsc, + ptrl->status == STATUS_WILLSEND ? "WILLSEND" : + ptrl->status == STATUS_SKIP ? "SKIP" : + ptrl->status == STATUS_SKIP ? "SENDING" : + ptrl->status == STATUS_SENT ? "SENT" : "?")); + } + DEB((D_OUTBOUND, "log_filelist: END")); +} + +void log_fsqueue(const s_fsqueue *q) +{ + int i; + + DEB((D_OUTBOUND, "log_queue_long: BEGIN")); + + log_filelist(q->fslist); + + for( i = 0; i < q->flonum; i++ ) + DEB((D_OUTBOUND, "log_queue_long: FLO file \"%s\"", q->flotab[i].fname)); + + DEB((D_OUTBOUND, "log_queue_long: END")); +} + +#endif diff --git a/source/bforce/outb_getname.c b/source/bforce/outb_getname.c new file mode 100644 index 0000000..7259853 --- /dev/null +++ b/source/bforce/outb_getname.c @@ -0,0 +1,111 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "outbound.h" + +char *out_getname_4d(s_faddr addr) +{ + s_cval_entry *cfptr = NULL; + char *p_outbound = NULL; + char *out_root = NULL; + char *out_main = NULL; + char *dest = NULL; + char buf[128]; + s_faddr mainaddr; + + p_outbound = conf_string(cf_outbound_directory); + + if( (cfptr = conf_first(cf_address)) ) + mainaddr = cfptr->d.falist.addr; + else + memset(&mainaddr, '\0', sizeof(s_faddr)); + + if( p_outbound && *p_outbound && cfptr + && out_get_root(p_outbound, &out_root, &out_main) == 0 + && out_root && *out_root && out_main && *out_main ) + { + if( addr.zone == mainaddr.zone ) + { + /* It is our primary outbound */ + if( addr.point == 0 ) + sprintf(buf, "%04x%04x", addr.net, addr.node); + else + sprintf(buf, "%04x%04x.pnt/%08x", addr.net, addr.node, addr.point); + + dest = string_concat(p_outbound, buf, NULL); + } + else + { + if( addr.point == 0 ) + sprintf(buf, ".%03x/%04x%04x", addr.zone, addr.net, addr.node); + else + sprintf(buf, ".%03x/%04x%04x.pnt/%08x", addr.zone, addr.net, addr.node, addr.point); + + dest = string_concat(out_root, out_main, buf, NULL); + } + } + + if( out_root ) free(out_root); + if( out_main ) free(out_main); + + return(dest); +} + +char *out_getname_domain(s_faddr addr) +{ + s_cval_entry *cfptr; + char buf[128]; + char *dest = NULL; + + /* find corresponding domain outbound.. */ + for( cfptr = conf_first(cf_domain); cfptr; + cfptr = conf_next(cfptr) ) + { + if( cfptr->d.domain.zone == addr.zone ) + { + /* first of all get file name */ + if( addr.point == 0 ) + sprintf(buf, "%04x%04x", addr.net, addr.node); + else + sprintf(buf, "%04x%04x.pnt/%08x", addr.net, addr.node, addr.point); + + dest = string_concat(cfptr->d.domain.path, buf, NULL); + break; + } + } + + return dest; +} + +char *out_getname_amiga(s_faddr addr) +{ + char buf[128]; + char *p_amigaoutbound = NULL; + char *dest = NULL; + + p_amigaoutbound = conf_string(cf_amiga_outbound_directory); + + if( p_amigaoutbound && *p_amigaoutbound ) + { + sprintf(buf, "%d.%d.%d.%d", addr.zone, addr.net, addr.node, addr.point); + dest = string_concat(p_amigaoutbound, buf, NULL); + } + + return dest; +} + +/* end */ diff --git a/source/bforce/outb_scan.c b/source/bforce/outb_scan.c new file mode 100644 index 0000000..c620d46 --- /dev/null +++ b/source/bforce/outb_scan.c @@ -0,0 +1,522 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "outbound.h" + +s_exttab outtab[] = +{ + { ".iut", TYPE_NETMAIL, FLAVOR_IMMED, ACTION_UNLINK }, + { ".cut", TYPE_NETMAIL, FLAVOR_CRASH, ACTION_UNLINK }, + { ".dut", TYPE_NETMAIL, FLAVOR_DIRECT, ACTION_UNLINK }, + { ".out", TYPE_NETMAIL, FLAVOR_NORMAL, ACTION_UNLINK }, + { ".hut", TYPE_NETMAIL, FLAVOR_HOLD, ACTION_UNLINK }, + { ".ikt", TYPE_NETMAIL, FLAVOR_IMMED, ACTION_UNLINK }, + { ".ckt", TYPE_NETMAIL, FLAVOR_CRASH, ACTION_UNLINK }, + { ".dkt", TYPE_NETMAIL, FLAVOR_DIRECT, ACTION_UNLINK }, + { ".pkt", TYPE_NETMAIL, FLAVOR_NORMAL, ACTION_UNLINK }, + { ".hkt", TYPE_NETMAIL, FLAVOR_HOLD, ACTION_UNLINK }, + { ".ilo", TYPE_FLOFILE, FLAVOR_IMMED, ACTION_NOTHING }, + { ".clo", TYPE_FLOFILE, FLAVOR_CRASH, ACTION_NOTHING }, + { ".dlo", TYPE_FLOFILE, FLAVOR_DIRECT, ACTION_NOTHING }, + { ".flo", TYPE_FLOFILE, FLAVOR_NORMAL, ACTION_NOTHING }, + { ".hlo", TYPE_FLOFILE, FLAVOR_HOLD, ACTION_NOTHING }, + { ".req", TYPE_REQUEST, FLAVOR_NONE, ACTION_NOTHING }, + { NULL, 0, 0, 0 } +}; + +s_exttab exttab[] = +{ + { ".tic", TYPE_TICFILE, FLAVOR_NORMAL, ACTION_TRUNCATE }, + { ".su?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE }, + { ".mo?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE }, + { ".tu?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE }, + { ".we?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE }, + { ".th?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE }, + { ".fr?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE }, + { ".sa?", TYPE_ARCMAIL, FLAVOR_NORMAL, ACTION_TRUNCATE }, + { NULL, 0, 0, 0 } +}; + +/***************************************************************************** + * Devide full outbound path on "root" directory, there other oubound + * directories created, and main outbound directory name + * + * Arguments: + * path pointer to the null-terminated outbound path string + * out_root pointer to the pointer for the resulting root directory + * out_main pointer to the pointer for the resulting main outbound + * name w/o path + * + * Return value: + * Zero on success (*out_root and *out_main must be freed) + */ +int out_get_root(const char *path, char **out_root, char **out_main) +{ + char *p, *outb; + + ASSERT(path != NULL && out_root != NULL && out_main != NULL); + + *out_root = NULL; + *out_main = NULL; + + outb = (char *)xstrcpy(path); + + p = outb + strlen(outb) - 1; + if( *p == DIRSEPCHR ) + *p = '\0'; + + /* Ohh.. where is no full path for outbound directory */ + if( (p=strrchr(outb, DIRSEPCHR)) == NULL ) + { + free(outb); + return -1; + } + + *p = '\0'; + *out_main = xstrcpy(p+1); + *out_root = xstrcat(outb, "/"); + + DEB((D_OUTBOUND, "out_getroot: out_root \"%s\", out_main \"%s\"", + *out_root, *out_main)); + + return 0; +} + +/***************************************************************************** + * Scan Binkley Style Outbound directory, for each file for requested + * addresses call callback function + * + * Arguments: + * callback pointer to the callback information structure + * fa_list pointer to the requested addresses list + * addr current address (most time it is partially filled) + * path path for the outbound to scan + * point point number for the current outbound + * + * Return value: + * Zero on success + */ +static int out_scan_bso_dir(s_outbound_callback_data *callback, + const s_falist *fa_list, s_faddr *addr, const char *path, int point) +{ + DIR *dir; + struct dirent *dirent; + char *p; + const s_falist *alst; + + ASSERT(callback); + ASSERT(callback->dest); + ASSERT(addr && path); + + DEB((D_OUTBOUND, "out_scan_bso_dir: BSO: scan dir \"%s\"", path)); + + if( (dir=opendir(path)) == NULL ) + { + logerr("can't open outbound directory \"%s\"", path); + return(1); + } + + while( (dirent=readdir(dir)) != NULL ) + { + if( strlen(dirent->d_name) == 12 && + strspn(dirent->d_name, "0123456789abcdefABCDEF") == 8 ) + { + if((strncasecmp(dirent->d_name+8, ".PNT", 4) != 0) && + ( strncasecmp(dirent->d_name+8, ".REQ", 4) != 0) && + ( strncasecmp(dirent->d_name+10, "UT", 2) != 0) && + ( strncasecmp(dirent->d_name+10, "LO", 2) != 0) ) continue; + if( point == 0 && strncasecmp(dirent->d_name+8, ".PNT", 4) == 0 ) + { + DEB((D_OUTBOUND, "scan_dir: BSO: found point directory \"%s\"", + dirent->d_name)); + + /* + * Congratulation, we found point's direcory + */ + sscanf(dirent->d_name, "%04x%04x", &addr->net, &addr->node); + for( alst = fa_list; alst; alst = alst->next ) + if( addr->net == alst->addr.net + && addr->node == alst->addr.node ) + break; + + if( alst || !fa_list ) + { + p = string_concat(path, dirent->d_name, "/", NULL); + out_scan_bso_dir(callback, fa_list, addr, p, 1); + if( p ) { free(p); p = NULL; } + } + } + else + { + if( point ) + { + sscanf(dirent->d_name, "%08x", &addr->point); + } + else + { + addr->point = 0; + sscanf(dirent->d_name, "%04x%04x", &addr->net, &addr->node); + } + + /* Check, does we really need in this file? */ + for( alst = fa_list; alst && ftn_addrcomp(*addr, alst->addr); + alst = alst->next ); + + if( alst || !fa_list ) + { + callback->path = string_concat(path, dirent->d_name, NULL); + callback->addr = *addr; + callback->type = OUTB_TYPE_BSO; + callback->flavor = -1; + callback->callback(callback); + if( callback->path ) + free(callback->path); + } + } + } + } + + closedir(dir); + + return(0); +} + +static int out_scan_bso(s_outbound_callback_data *callback, + const s_falist *mailfor, const char *path) +{ + DIR *dir; + struct dirent *dirent; + const s_falist *alst; + s_faddr addr; + char *newpath; + char *out_root = NULL; /* Root for outbound directories tree */ + char *out_main = NULL; /* Main outbound directory name */ + int len; + + ASSERT(path); + + if( out_get_root(path, &out_root, &out_main) ) + return -1; + + ASSERT(out_root && out_main); + + if( (dir = opendir(out_root)) == NULL ) + { + logerr("can't open outbound directory \"%s\"", out_root); + free(out_root); free(out_main); + return -1; + } + + /* Scan outbound (only 4D) */ + while( (dirent = readdir(dir)) ) + { + memset(&addr, '\0', sizeof(s_faddr)); + if( strcmp(dirent->d_name, out_main) == 0 ) + { + /* Our main outbound */ + s_cval_entry *cfptr = conf_first(cf_address); + if( cfptr ) + addr.zone = cfptr->d.falist.addr.zone; + else + addr.zone = 666; + } + else if( strncmp(dirent->d_name, out_main, len=strlen(out_main)) == 0 + && dirent->d_name[len] == '.' + && strspn(dirent->d_name+len+1,"0123456789abcdefABCDEF") == 3 ) + { + /* Ooutbound with zone ext. (like /outbound.308/) */ + sscanf(dirent->d_name+len+1, "%03x", &addr.zone); + } + + if( addr.zone ) + { + for( alst = mailfor; + alst && addr.zone != alst->addr.zone; + alst = alst->next ); + + if( alst || mailfor == NULL ) + { + newpath = string_concat(out_root, dirent->d_name, "/", NULL); + out_scan_bso_dir(callback, mailfor, &addr, newpath, 0); + free(newpath); + } + } + } + + closedir(dir); + + free(out_root); + free(out_main); + + return 0; +} + +static int out_parse_name_lbox(s_faddr *addr, const char *filename) +{ + s_faddr tmp; + + ASSERT(addr && filename); + + memset(&tmp, '\0', sizeof(s_faddr)); + if( sscanf(filename, "%d.%d.%d.%d", + &tmp.zone, &tmp.net, &tmp.node, &tmp.point) == 4 ) + { + *addr = tmp; + return 0; + } + + return -1; +} + +static int out_scan_fbox_dir(s_outbound_callback_data *callback, + const char *path, s_faddr addr, int flavor) +{ + DIR *dir; + struct dirent *dirent; + + if( (dir = opendir(path)) == NULL ) + { + logerr("can't open filebox directory \"%s\"", path); + return -1; + } + + while( (dirent = readdir(dir)) ) + { + callback->path = string_concat(path, dirent->d_name, NULL); + if( is_regfile(callback->path) ) + { + callback->addr = addr; + callback->type = OUTB_TYPE_FBOX; + callback->flavor = flavor; + callback->callback(callback); + } + free(callback->path); + callback->path = NULL; + } + + closedir(dir); + + return 0; +} + +static int out_scan_lbox(s_outbound_callback_data *callback, + const s_falist *mailfor, const char *path) +{ + DIR *dir; + struct dirent *dirent; + const s_falist *alst; + s_faddr addr; + char *newpath; + + if( (dir = opendir(path)) == NULL ) + { + logerr("can't open filebox directory \"%s\"", path); + return -1; + } + + while( (dirent = readdir(dir)) ) + { + if( out_parse_name_lbox(&addr, dirent->d_name) == 0 ) + { + if( mailfor ) + { + /* Scan only this fileboxes */ + for( alst = mailfor; + alst && ftn_addrcomp(addr, alst->addr); + alst = alst->next ); + if( alst ) + { + newpath = string_concat(path, dirent->d_name, "/", NULL); + (void)out_scan_fbox_dir(callback, newpath, addr, FLAVOR_HOLD); + free(newpath); + } + } + else + { + /* Scan all fileboxes */ + newpath = string_concat(path, dirent->d_name, "/", NULL); + (void)out_scan_fbox_dir(callback, newpath, addr, FLAVOR_HOLD); + free(newpath); + } + } + } + + closedir(dir); + + return 0; +} + +/***************************************************************************** + * Parse file name from AmigaDos Style Outbound + * + * Arguments: + * name pointer to the null-terminated file name + * addr pointer to the memory where to store resulting address + * + * Return value: + * Zero on success + */ +int out_parse_name_aso(s_faddr *addr, const char *filename) +{ + s_faddr tmp; + + ASSERT(addr && filename); + + memset(&tmp, '\0', sizeof(s_faddr)); + if( sscanf(filename, "%d.%d.%d.%d.%*s", &tmp.zone, + &tmp.net, &tmp.node, &tmp.point) == 4 ) + { + *addr = tmp; + return 0; + } + + return -1; +} + +static int out_scan_aso(s_outbound_callback_data *callback, + const s_falist *mailfor, const char *path) +{ + DIR *dir; + struct dirent *dirent; + const s_falist *alst; + s_faddr addr = { FALSE, 0, 0, 0, 0, "" }; +#ifdef DEBUG + char abuf[BF_MAXADDRSTR+1]; +#endif + + ASSERT(callback); + ASSERT(callback->dest); + ASSERT(path); + + DEB((D_OUTBOUND, "out_scandir_aso: scan dir \"%s\"", path)); + + if( (dir = opendir(path)) == NULL ) + { + logerr("can't open outbound directory \"%s\"", path); + return -1; + } + + while( (dirent = readdir(dir)) ) + { + memset(&addr, '\0', sizeof(s_faddr)); + + if( out_parse_name_aso(&addr, dirent->d_name) == 0 ) + { + DEB((D_OUTBOUND, "out_scandir_aso: file \"%s\" for address %s", + dirent->d_name, ftn_addrstr(abuf, addr))); + + for( alst = mailfor; alst && ftn_addrcomp(addr, alst->addr); + alst = alst->next ); + + if( alst || !mailfor ) + { + callback->path = string_concat(path, dirent->d_name, NULL); + callback->addr = addr; + callback->type = OUTB_TYPE_ASO; + callback->flavor = -1; + callback->callback(callback); + if( callback->path ) + free(callback->path); + } + } + } + + closedir(dir); + + return 0; +} + +/* ------------------------------------------------------------------------- */ +/* Scan outbound for addresses fa_list, use handler proc */ +/* ------------------------------------------------------------------------- */ +int out_scan(s_outbound_callback_data *callback, const s_falist *fa_list) +{ + const s_falist *alst; + s_faddr addr = { FALSE, 0, 0, 0, 0, "" }; + s_cval_entry *cfptr; + char *path; + + ASSERT(callback); + ASSERT(callback->callback); + ASSERT(callback->dest); + + /* + * 1st - try out 4D outbound + */ + path = conf_string(cf_outbound_directory); + if( path && *path ) + (void)out_scan_bso(callback, fa_list, path); + + /* + * 2th - Scan domain outbounds + */ + for( cfptr = conf_first(cf_domain); cfptr; cfptr = conf_next(cfptr) ) + { + memset(&addr, '\0', sizeof(s_faddr)); + for( alst = fa_list; alst; alst = alst->next ) + { + if( cfptr->d.domain.zone == alst->addr.zone + || alst->addr.zone == -1 ) + { + addr.zone = cfptr->d.domain.zone; + out_scan_bso_dir(callback, fa_list, &addr, + cfptr->d.domain.path, 0); + break; + } + } + } + + /* + * 3th - Scan AmigaDOS outbound + */ + path = conf_string(cf_amiga_outbound_directory); + if( path && *path ) + (void)out_scan_aso(callback, fa_list, path); + + /* + * 4th - Scan personal fileboxes + */ + if( fa_list ) + { + /* Scan only listed fileboxes */ + for( cfptr = conf_first(cf_filebox); cfptr; cfptr = conf_next(cfptr) ) + { + for( alst = fa_list; alst; alst = alst->next ) + { + if( !ftn_addrcomp(alst->addr, cfptr->d.filebox.addr) ) + out_scan_fbox_dir(callback, cfptr->d.filebox.path, + cfptr->d.filebox.addr, cfptr->d.filebox.flavor); + } + } + } + else + { + /* Scan all fileboxes */ + for( cfptr = conf_first(cf_filebox); cfptr; cfptr = conf_next(cfptr) ) + out_scan_fbox_dir(callback, cfptr->d.filebox.path, + cfptr->d.filebox.addr, cfptr->d.filebox.flavor); + } + + /* + * 5th - Scan "long" fileboxes + */ + path = conf_string(cf_filebox_directory); + if( path && *path ) + (void)out_scan_lbox(callback, fa_list, path); + + return(0); +} diff --git a/source/bforce/outb_sysqueue.c b/source/bforce/outb_sysqueue.c new file mode 100644 index 0000000..fb3ef5a --- /dev/null +++ b/source/bforce/outb_sysqueue.c @@ -0,0 +1,302 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "outbound.h" + +/* + * Will call this function than add new entry to the queue + */ +int (*sysqueue_add_callback)(s_sysentry *) = NULL; + +/* + * Will call this function than remove entry from the queue + */ +int (*sysqueue_rem_callback)(s_sysentry *) = NULL; + +/* + * Set this to disable mail/files size count + */ +bool sysqueue_dont_count_sizes = FALSE; + +/* + * Return TRUE if 'chk' entry must be before 'max' in the queue + */ +static bool out_sysqueue_sort_comp(s_sysentry *max, s_sysentry *chk, int opts) +{ + if( opts & QUEUE_SORT_ADDRESS ) + { + if( opts & QUEUE_SORT_REVERSE ) + return !ftn_addrcomp_logic(max->node.addr, ADDR_LT, chk->node.addr); + else + return !ftn_addrcomp_logic(max->node.addr, ADDR_GT, chk->node.addr); + } + else if( opts & QUEUE_SORT_SIZE ) + { + size_t size_max = max->netmail_size + max->arcmail_size + + max->request_size + max->files_size; + size_t size_chk = chk->netmail_size + chk->arcmail_size + + chk->request_size + chk->files_size; + + if( opts & QUEUE_SORT_REVERSE ) + return size_max > size_chk; + else + return size_max < size_chk; + } + + return FALSE; +} + +void out_sysqueue_sort(s_sysqueue *q, int opts) +{ + int i, j, max; + s_sysentry tmp; + + if( q->sysnum < 2 ) return; + + for( i = 0; i < q->sysnum - 1; i++ ) + { + for( max = i, j = i + 1; j < q->sysnum; j++ ) + if( out_sysqueue_sort_comp(&q->systab[max], &q->systab[j], opts) ) + max = j; + + if( max > i ) + { + tmp = q->systab[max]; + q->systab[max] = q->systab[i]; + q->systab[i] = tmp; + } + } +} + +void out_reset_sysqueue(s_sysqueue *q) +{ + int i; + + for( i = 0; i < q->sysnum; i++ ) + { + q->systab[i].netmail_size = 0; + q->systab[i].request_size = 0; + q->systab[i].arcmail_size = 0; + q->systab[i].files_size = 0; + q->systab[i].flavors = 0; + q->systab[i].types = 0; + } +} + +void out_remove_from_sysqueue(s_sysqueue *q, int pos) +{ + ASSERT(q && pos >= 0 && pos < q->sysnum); + + if( sysqueue_rem_callback ) + (void)sysqueue_rem_callback(&q->systab[pos]); + + if( q->sysnum > 1 ) + { + memmove(&q->systab[pos], &q->systab[pos + 1], + sizeof(s_sysentry)*(q->sysnum - pos - 1)); + q->systab = xrealloc(q->systab, + sizeof(s_sysentry)*(q->sysnum - 1)); + --q->sysnum; + } + else + { + free(q->systab); + q->systab = NULL; + q->sysnum = 0; + } +} + +/* + * Return pointer to entry in systems list for address addr + */ +static s_sysentry *out_getsysentry(s_sysqueue *q, s_faddr addr) +{ + int i; + + for( i = 0; i < q->sysnum; i++ ) + if( ftn_addrcomp(q->systab[i].node.addr, addr) == 0 ) + return &q->systab[i]; + + /* Add new entry for new address */ + + q->systab = (s_sysentry*)xrealloc(q->systab, sizeof(s_sysentry)*(q->sysnum+1)); + + memset(&q->systab[q->sysnum], '\0', sizeof(s_sysentry)); + q->systab[q->sysnum].node.addr = addr; + + if( sysqueue_add_callback ) + (void)sysqueue_add_callback(&q->systab[i]); + + return &q->systab[q->sysnum++]; +} + +/* ------------------------------------------------------------------------- */ +/* Handle each file $fi found in outbound. Usually it called by outbound */ +/* scanner.. Pointer to result information will be stored at dst */ +/* ------------------------------------------------------------------------- */ +int out_handle_sysqueue(s_outbound_callback_data *callback) +{ + s_sysentry *sentry; + int type; + int flavor; + + ASSERT(callback); + ASSERT(callback->path); + ASSERT(callback->dest); + + DEB((D_OUTBOUND, "out_handle_sysqueue: process file \"%s\"", + callback->path)); + + if( callback->type != OUTB_TYPE_FBOX ) + { + int i; + const char *p_ext = strrchr(callback->path, '.'); + + if( !p_ext ) + return -1; + + for( i = 0; outtab[i].ext && strcasecmp(p_ext, outtab[i].ext); i++ ); + if( !outtab[i].ext ) + return -1; + + type = outtab[i].type; + flavor = outtab[i].flavor; + } + else + { + type = TYPE_FILEBOX; + if( callback->flavor != -1 ) + flavor = callback->flavor; + else + flavor = FLAVOR_HOLD; + } + + /* Try to found existing entry for this address */ + if( (sentry = out_getsysentry((s_sysqueue*)callback->dest, + callback->addr)) == NULL ) + return -1; + + if( type == TYPE_NETMAIL || type == TYPE_REQUEST || type == TYPE_FILEBOX ) + { + struct stat st; + + sentry->flavors |= flavor; + sentry->types |= type; + + if( !sysqueue_dont_count_sizes ) + { + if( stat(callback->path, &st) == 0 ) + { + /* Update mail age */ + if( st.st_mtime > sentry->mailage ) + sentry->mailage = st.st_mtime; + + /* Update mail size */ + if( type & TYPE_NETMAIL ) + sentry->netmail_size += st.st_size; + else if( type & TYPE_ARCMAIL ) + sentry->arcmail_size += st.st_size; + else if( type & TYPE_REQUEST ) + sentry->request_size += st.st_size; + else + sentry->files_size += st.st_size; + } + else + logerr("can't stat file \"%s\"", callback->path); + } + } + else if( type == TYPE_FLOFILE ) + { + sentry->flavors |= flavor; + + if( !sysqueue_dont_count_sizes ) + { + s_FLO *FLO; + + if( (FLO = flo_open(callback->path, "r")) == NULL ) + { + logerr("can't open flo \"%s\"", callback->path); + return -1; + } + + while( flo_next(FLO) == 0 ) + { + struct stat st; + + if( stat(FLO->att_path, &st) == 0 ) + { + /* Update mail age */ + if( st.st_mtime > sentry->mailage ) + sentry->mailage = st.st_mtime; + + /* Update mail size */ + if( out_filetype(FLO->att_path) & TYPE_ARCMAIL ) + sentry->arcmail_size += st.st_size; + else + sentry->files_size += st.st_size; + } + } + flo_close(FLO); + } + } + else + log("skipping file of unknown type \"%s\"", callback->path); + + return 0; +} + +void deinit_sysqueue(s_sysqueue *q) +{ + if( q->systab ) free(q->systab); + memset(q, '\0', sizeof(s_sysqueue)); +} + +#ifdef DEBUG +void log_sysqueue(const s_sysqueue *q) +{ + char abuf[BF_MAXADDRSTR+1]; + char tmp[256] = ""; + int i; + + DEB((D_OUTBOUND, "log_sysqueue: BEGIN")); + for( i = 0; i < q->sysnum; i++ ) + { + DEB((D_OUTBOUND, "log_sysqueue: address %s", ftn_addrstr(abuf, q->systab[i].node.addr))); + + tmp[0] = '\0'; + + if( q->systab[i].flavors & FLAVOR_IMMED ) strcat(tmp, "Immediate,"); + if( q->systab[i].flavors & FLAVOR_CRASH ) strcat(tmp, "Crash,"); + if( q->systab[i].flavors & FLAVOR_NORMAL ) strcat(tmp, "Normal,"); + if( q->systab[i].flavors & FLAVOR_HOLD ) strcat(tmp, "Hold,"); + if( tmp[0] ) tmp[strlen(tmp)-1] = '\0'; + DEB((D_OUTBOUND, "log_sysqueue: \tflavors: \"%s\"", tmp)); + + tmp[0] = '\0'; + if( q->systab[i].types & TYPE_NETMAIL ) strcat(tmp, "netmail,"); + if( q->systab[i].types & TYPE_FLOFILE ) strcat(tmp, "flofile,"); + if( q->systab[i].types & TYPE_ARCMAIL ) strcat(tmp, "arcmail,"); + if( q->systab[i].types & TYPE_REQUEST ) strcat(tmp, "request,"); + if( q->systab[i].types & TYPE_FILEECHO ) strcat(tmp, "fileecho,"); + if( q->systab[i].types & TYPE_FILEBOX ) strcat(tmp, "filebox,"); + if( q->systab[i].types & TYPE_FROMFLO ) strcat(tmp, "fromflo,"); + if( tmp[0] ) tmp[strlen(tmp)-1] = '\0'; + DEB((D_OUTBOUND, "log_sysqueue: \ttypes: \"%s\"", tmp)); + } + DEB((D_OUTBOUND, "log_sysqueue: END")); +} +#endif diff --git a/source/bforce/prot_binkp.c b/source/bforce/prot_binkp.c new file mode 100644 index 0000000..03d6d90 --- /dev/null +++ b/source/bforce/prot_binkp.c @@ -0,0 +1,698 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "io.h" +#include "session.h" +#include "outbound.h" +#include "prot_common.h" +#include "prot_binkp.h" + +typedef enum { + BPI_SendSysInfo, + BPI_WaitADR, + BPI_WaitPWD, + BPI_Auth +} binkp_incoming_state; + +typedef enum { + BPO_SendSysInfo, + BPO_WaitNUL, + BPO_SendPWD, + BPO_WaitADR, + BPO_Auth, + BPO_WaitOK +} binkp_outgoing_state; + +#define GOTO(label,newrc) { rc = (newrc); goto label; } + +void binkp_process_NUL(s_binkp_sysinfo *remote_data, char *buffer) +{ + char *p, *q; + + if( strncmp(buffer, "SYS ", 4) == 0 ) + strnxcpy(remote_data->systname, buffer+4, sizeof(remote_data->systname)); + else if( strncmp(buffer, "ZYZ ", 4) == 0 ) + strnxcpy(remote_data->sysop, buffer+4, sizeof(remote_data->sysop)); + else if( strncmp(buffer, "LOC ", 4) == 0 ) + strnxcpy(remote_data->location, buffer+4, sizeof(remote_data->location)); + else if( strncmp(buffer, "PHN ", 4) == 0 ) + strnxcpy(remote_data->phone, buffer+4, sizeof(remote_data->phone)); + else if( strncmp(buffer, "NDL ", 4) == 0 ) + strnxcpy(remote_data->flags, buffer+4, sizeof(remote_data->flags)); + else if( strncmp(buffer, "TIME ", 5) == 0 ) + strnxcpy(remote_data->timestr, buffer+5, sizeof(remote_data->timestr)); + else if( strncmp(buffer, "OPT ", 4) == 0 ) + { + if( *remote_data->opt ) + { + strnxcat(remote_data->opt, " ", sizeof(remote_data->opt)); + strnxcat(remote_data->opt, buffer+4, sizeof(remote_data->opt)); + } + else + strnxcpy(remote_data->opt, buffer+4, sizeof(remote_data->opt)); + + binkp_parse_options(remote_data, buffer+4); + } + else if( strncmp(buffer, "VER ", 4) == 0 ) + { + /* [/.] */ + if( (p = strchr(buffer+4, ' ')) ) + { + strnxcpy(remote_data->progname, buffer+4, + MIN(sizeof(remote_data->progname), p - (buffer+4) + 1)); + ++p; + if( (q = strchr(p, '/')) ) + { + strnxcpy(remote_data->protname, p, + MIN(sizeof(remote_data->protname), q - p + 1)); + sscanf(q+1, "%d.%d", + &remote_data->majorver, + &remote_data->minorver); + } + } + else + strnxcpy(remote_data->progname, buffer+4, sizeof(remote_data->progname)); + } + else + log("BinkP got invalid NUL: \"%s\"", string_printable(buffer)); +} + +void binkp_process_ADR(s_binkp_sysinfo *remote_data, char *buffer) +{ + s_faddr addr; + char *p, *q; + + for( p = string_token(buffer, &q, NULL, 0); p; + p = string_token(NULL, &q, NULL, 0) ) + { + if( ftn_addrparse(&addr, p, FALSE) ) + log("BinkP got unparsable address \"%s\"", string_printable(p)); + else + session_addrs_add(&remote_data->addrs, &remote_data->anum, addr); + } +} + +int binkp_outgoing(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data) +{ + s_bpinfo bpi; + binkp_outgoing_state binkp_state = BPO_SendSysInfo; + int rc = HRC_OK; + int recv_rc = 0; + int send_rc = 0; + bool send_ready = FALSE; + bool recv_ready = FALSE; + + binkp_init_bpinfo(&bpi); + + while(1) + { + switch(binkp_state) { + case BPO_SendSysInfo: + binkp_queue_sysinfo(&bpi, local_data); + binkp_state = BPO_WaitNUL; + break; + + case BPO_SendPWD: + if( *local_data->passwd == '\0' ) + { + binkp_queuemsg(&bpi, BPMSG_PWD, NULL, "-"); + } + else if( remote_data->options & BINKP_OPT_MD5 ) + { + char digest_bin[16]; + char digest_hex[33]; + + md5_cram_get(local_data->passwd, remote_data->challenge, + remote_data->challenge_length, digest_bin); + + /* Encode digest to the hex string */ + string_bin_to_hex(digest_hex, digest_bin, 16); + + binkp_queuemsg(&bpi, BPMSG_PWD, "CRAM-MD5-", digest_hex); + } + else + binkp_queuemsg(&bpi, BPMSG_PWD, NULL, local_data->passwd); + + binkp_state = BPO_WaitADR; + break; + + case BPO_Auth: + /* Set remote password same as local */ + strncpy(remote_data->passwd, local_data->passwd, BINKP_MAXPASSWD); + remote_data->passwd[BINKP_MAXPASSWD] = '\0'; + + if( !remote_data->anum ) + { + binkp_queuemsg(&bpi, BPMSG_BSY, NULL, "No addresses was presented"); + GOTO(Exit, HRC_BUSY); + } + else if( session_addrs_check_genuine(remote_data->addrs, remote_data->anum, + state.node.addr) ) + { + binkp_queuemsg(&bpi, BPMSG_ERR, NULL, "Sorry, you are not who I need"); + GOTO(Exit, HRC_NO_ADDRESS); + } + else if( session_addrs_check(remote_data->addrs, remote_data->anum, + remote_data->passwd, NULL, 0) ) + { + binkp_queuemsg(&bpi, BPMSG_ERR, NULL, "Security violation"); + GOTO(Exit, HRC_BAD_PASSWD); + } + else if( session_addrs_lock(remote_data->addrs, remote_data->anum) ) + { + binkp_queuemsg(&bpi, BPMSG_BSY, NULL, "All addresses are busy"); + GOTO(Exit, HRC_BUSY); + } + binkp_state = BPO_WaitOK; + break; + + default: + break; + } + + /* + * Receive/Send next data block + */ + send_ready = recv_ready = FALSE; + + if( tty_select(&recv_ready, (bpi.opos || bpi.n_msgs) ? + &send_ready : NULL, bpi.timeout) < 0 ) + GOTO(Abort, HRC_OTHER_ERR); + + recv_rc = BPMSG_NONE; + send_rc = 0; + + if( recv_ready && (recv_rc = binkp_recv(&bpi)) == BPMSG_EXIT ) + GOTO(Abort, HRC_OTHER_ERR); + + if( send_ready && (send_rc = binkp_send(&bpi)) < 0 ) + GOTO(Abort, HRC_OTHER_ERR); + + /* + * Handle received message + */ + switch(recv_rc) { + case BPMSG_NONE: + break; + + case BPMSG_NUL: + if( binkp_state == BPO_WaitNUL || binkp_state == BPO_WaitADR ) + { + binkp_process_NUL(remote_data, bpi.ibuf+1); + if( binkp_state == BPO_WaitNUL ) + binkp_state = BPO_SendPWD; + } + break; + + case BPMSG_ADR: + if( binkp_state == BPO_WaitADR ) + { + binkp_process_ADR(remote_data, bpi.ibuf+1); + binkp_state = BPO_Auth; + } + break; + + case BPMSG_OK: + if( binkp_state == BPO_WaitOK ) + GOTO(Exit, HRC_OK); + break; + + case BPMSG_ERR: + log("BinkP error: \"%s\"", string_printable(bpi.ibuf+1)); + GOTO(Abort, HRC_FATAL_ERR); + + case BPMSG_BSY: + log("BinkP busy: \"%s\"", string_printable(bpi.ibuf+1)); + GOTO(Abort, HRC_TEMP_ERR); + } + } + +Exit: + if( binkp_flush_queue(&bpi, bpi.timeout) && rc == HRC_OK ) + rc = HRC_OTHER_ERR; + +Abort: + binkp_deinit_bpinfo(&bpi); + + return rc; +} + + +int binkp_auth_incoming(s_binkp_sysinfo *remote_data) +{ + if( remote_data->challenge_length > 0 + && strncmp(remote_data->passwd, "CRAM-MD5-", 9) == 0 ) + { + return session_addrs_check(remote_data->addrs, + remote_data->anum, + remote_data->passwd + 9, + remote_data->challenge, + remote_data->challenge_length); + } + + return session_addrs_check(remote_data->addrs, remote_data->anum, + remote_data->passwd, NULL, 0); +} + +int binkp_incoming(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data) +{ + s_bpinfo bpi; + binkp_incoming_state binkp_state = BPI_SendSysInfo; + int rc = HRC_OK; + int recv_rc = 0; + int send_rc = 0; + bool send_ready = FALSE; + bool recv_ready = FALSE; + + binkp_init_bpinfo(&bpi); + + while(1) + { + switch(binkp_state) { + case BPI_SendSysInfo: + binkp_queue_sysinfo(&bpi, local_data); + binkp_state = BPI_WaitADR; + break; + + case BPI_Auth: + /* Set challenge string same as local */ + memcpy(remote_data->challenge, local_data->challenge, + sizeof(remote_data->challenge)); + remote_data->challenge_length = local_data->challenge_length; + + /* Do authorization */ + if( !remote_data->anum ) + { + binkp_queuemsg(&bpi, BPMSG_BSY, NULL, "No addresses was presented"); + GOTO(Exit, HRC_BUSY); + } + else if( binkp_auth_incoming(remote_data) ) + { + binkp_queuemsg(&bpi, BPMSG_ERR, NULL, "Security violation"); + GOTO(Exit, HRC_BAD_PASSWD); + } + else if( session_addrs_lock(remote_data->addrs, remote_data->anum) ) + { + binkp_queuemsg(&bpi, BPMSG_BSY, NULL, "All addresses are busy"); + GOTO(Exit, HRC_BUSY); + } + else + { + binkp_queuemsg(&bpi, BPMSG_OK, NULL, NULL); + GOTO(Exit, HRC_OK); + } + break; + + default: + break; + } + + /* + * Receive/Send next data block + */ + send_ready = recv_ready = FALSE; + + if( tty_select(&recv_ready, (bpi.opos || bpi.n_msgs) ? + &send_ready : NULL, bpi.timeout) < 0 ) + GOTO(Abort, HRC_OTHER_ERR); + + recv_rc = BPMSG_NONE; + send_rc = 0; + + if( recv_ready && (recv_rc = binkp_recv(&bpi)) == BPMSG_EXIT ) + GOTO(Abort, HRC_OTHER_ERR); + + if( send_ready && (send_rc = binkp_send(&bpi)) < 0 ) + GOTO(Abort, HRC_OTHER_ERR); + + /* + * Handle received message + */ + switch(recv_rc) { + case BPMSG_NONE: + break; + + case BPMSG_NUL: + if( binkp_state == BPI_WaitADR ) + binkp_process_NUL(remote_data, bpi.ibuf+1); + break; + + case BPMSG_ADR: + if( binkp_state == BPI_WaitADR ) + { + binkp_process_ADR(remote_data, bpi.ibuf+1); + binkp_state = BPI_WaitPWD; + } + break; + + case BPMSG_PWD: + if( binkp_state == BPI_WaitPWD ) + { + strnxcpy(remote_data->passwd, bpi.ibuf+1, sizeof(remote_data->passwd)); + binkp_state = BPI_Auth; + } + break; + + case BPMSG_ERR: + log("BinkP error: \"%s\"", string_printable(bpi.ibuf+1)); + GOTO(Abort, HRC_FATAL_ERR); + + case BPMSG_BSY: + log("BinkP busy: \"%s\"", string_printable(bpi.ibuf+1)); + GOTO(Abort, HRC_TEMP_ERR); + } + } + +Exit: + if( binkp_flush_queue(&bpi, bpi.timeout) && rc == HRC_OK ) + rc = HRC_OTHER_ERR; + +Abort: + binkp_deinit_bpinfo(&bpi); + + return rc; +} + +int binkp_transfer(s_protinfo *pi) +{ + int i, n, rc = PRC_NOERROR; + bool recv_ready = FALSE; + bool send_ready = FALSE; + bool sent_EOB = FALSE; + bool rcvd_EOB = FALSE; + bool send_file = FALSE; + bool recv_file = FALSE; + bool wait_got = FALSE; + bool nofiles = FALSE; + int recv_rc = 0; + int send_rc = 0; + char *fname = NULL; + size_t fsize = 0; + time_t ftime = 0; + size_t foffs = 0; + s_bpinfo bpi; + + binkp_init_bpinfo(&bpi); + + while( !sent_EOB || !rcvd_EOB ) + { + if( !send_file && !sent_EOB && bpi.opos == 0 && bpi.n_msgs == 0 ) + { + if( !p_tx_fopen(pi) ) + { + send_file = TRUE; + binkp_queuemsgf(&bpi, BPMSG_FILE, "%s %ld %ld 0", + pi->send->net_name, (long)pi->send->bytes_total, + (long)pi->send->mod_time); + } + else + /* No more files */ + nofiles = TRUE; + } + + if( send_file && bpi.opos == 0 && bpi.n_msgs == 0 ) + { + if( (n = p_tx_readfile(bpi.obuf + BINKP_BLK_HDRSIZE, + 4096, pi)) < 0 ) + { + p_tx_fclose(pi); + send_file = FALSE; + } + else + { + binkp_puthdr(bpi.obuf, (unsigned)(n & 0x7fff)); + bpi.opos = n + BINKP_BLK_HDRSIZE; + pi->send->bytes_sent += n; + if( pi->send->eofseen ) + { + wait_got = TRUE; send_file = FALSE; + pi->send->status = FSTAT_WAITACK; + } + } + } + + if( nofiles && !wait_got && !sent_EOB ) + { + sent_EOB = TRUE; + binkp_queuemsg(&bpi, BPMSG_EOB, NULL, NULL); + } + + recv_ready = send_ready = FALSE; + if( tty_select(&recv_ready, (bpi.opos || bpi.n_msgs) ? + &send_ready : NULL, bpi.timeout) < 0 ) + gotoexit(PRC_ERROR); + + recv_rc = BPMSG_NONE; + send_rc = 0; + + if( recv_ready && (recv_rc = binkp_recv(&bpi)) == BPMSG_EXIT ) + gotoexit(PRC_ERROR); + if( send_ready && (send_rc = binkp_send(&bpi)) < 0 ) + gotoexit(PRC_ERROR); + + switch(recv_rc) { + case BPMSG_NONE: + break; + case BPMSG_DATA: /* Got new data block */ + if( recv_file ) + { + if( (n = p_rx_writefile(bpi.ibuf, bpi.isize, pi)) < 0 ) + { + /* error writing file */ + if( n == -2 ) + { + binkp_queuemsgf(&bpi, BPMSG_GOT, "%s %ld %ld", + pi->recv->net_name, (long)pi->recv->bytes_total, + (long)pi->recv->mod_time); + } + else + { + binkp_queuemsgf(&bpi, BPMSG_SKIP, "%s %ld %ld", + pi->recv->net_name, (long)pi->recv->bytes_total, + (long)pi->recv->mod_time); + } + recv_file = FALSE; + p_rx_fclose(pi); + } + else + { + pi->recv->bytes_received += bpi.isize; + + /* Was it the last data block? */ + if( pi->recv->bytes_received > pi->recv->bytes_total ) + { + log("binkp got too many data (%ld, %ld expected)", + (long)pi->recv->bytes_received, + (long)pi->recv->bytes_total); + + recv_file = FALSE; + pi->recv->status = FSTAT_REFUSED; + (void)p_rx_fclose(pi); + + binkp_queuemsgf(&bpi, BPMSG_SKIP, "%s %ld %ld", + pi->recv->net_name, (long)pi->recv->bytes_total, + (long)pi->recv->mod_time); + } + else if( pi->recv->bytes_received == pi->recv->bytes_total ) + { + recv_file = FALSE; + pi->recv->status = FSTAT_SUCCESS; + if( !p_rx_fclose(pi) ) + { + binkp_queuemsgf(&bpi, BPMSG_GOT, "%s %ld %ld", + pi->recv->net_name, (long)pi->recv->bytes_total, + (long)pi->recv->mod_time); + } + else + { + binkp_queuemsgf(&bpi, BPMSG_SKIP, "%s %ld %ld", + pi->recv->net_name, (long)pi->recv->bytes_total, + (long)pi->recv->mod_time); + } + } + } + } +#ifdef DEBUG + else + DEB((D_PROT, "ignore received data block")); +#endif + break; + + case BPMSG_FILE: + if( recv_file ) + { p_rx_fclose(pi); recv_file = FALSE; } + + if( binkp_parsfinfo(bpi.ibuf+1, &fname, + &fsize, &ftime, &foffs) ) + { + binkp_queuemsg(&bpi, BPMSG_ERR, "FILE: ", "unparsable arguments"); + goto FinishSession; + } + + if( pi->recv && !p_compfinfo(pi->recv, fname, fsize, ftime) + && pi->recv->bytes_skipped == foffs ) + { + recv_file = TRUE; + break; + } + + switch(p_rx_fopen(pi, fname, fsize, ftime, 0)) { + case 0: + if( pi->recv->bytes_skipped == 0 ) + { + recv_file = TRUE; + break; + } + binkp_queuemsgf(&bpi, BPMSG_GET, "%s %ld %ld %ld", + pi->recv->net_name, (long)pi->recv->bytes_total, + (long)pi->recv->mod_time, + (long)pi->recv->bytes_skipped); + break; + case 1: + /* SKIP (non-destructive) */ + binkp_queuemsgf(&bpi, BPMSG_SKIP, "%s %ld %ld", + pi->recv->net_name, (long)pi->recv->bytes_total, + (long)pi->recv->mod_time); + break; + case 2: + /* SKIP (destructive) */ + binkp_queuemsgf(&bpi, BPMSG_GOT, "%s %ld %ld", + pi->recv->net_name, (long)pi->recv->bytes_total, + (long)pi->recv->mod_time); + break; + default: + ASSERT_MSG(); + } + break; + + case BPMSG_EOB: /* End Of Batch */ + if( recv_file ) + { + p_rx_fclose(pi); + recv_file = FALSE; + } + rcvd_EOB = TRUE; + break; + + case BPMSG_GOT: + case BPMSG_SKIP: + if( binkp_parsfinfo(bpi.ibuf+1, &fname, &fsize, &ftime, NULL) == 0 ) + { + if( send_file && !p_compfinfo(pi->send, fname, fsize, ftime) ) + { + /* We got GOT/SKIP for current file! */ + if( recv_rc == BPMSG_GOT ) + pi->send->status = FSTAT_SKIPPED; + else + pi->send->status = FSTAT_REFUSED; + p_tx_fclose(pi); + send_file = FALSE; + break; + } + + wait_got = FALSE; + + for( i = 0; i < pi->n_sentfiles; i++ ) + { + if( pi->sentfiles[i].status == FSTAT_WAITACK + && !p_compfinfo(&pi->sentfiles[i], fname, fsize, ftime) ) + { + s_finfo *tmp = pi->send; + + pi->send = &pi->sentfiles[i]; + if( recv_rc == BPMSG_GOT ) + pi->send->status = FSTAT_SUCCESS; + else + pi->send->status = FSTAT_REFUSED; + p_tx_fclose(pi); + + pi->send = tmp; + break; + } + else if( pi->sentfiles[i].status == FSTAT_WAITACK ) + wait_got = TRUE; + } + + /* + * Check, maybe there are files still + * waiting for the GOT/SKIP acknwoledge + */ + while( i < pi->n_sentfiles && !wait_got ) + { + if( pi->sentfiles[i].status == FSTAT_WAITACK ) + wait_got = TRUE; + ++i; + } + } + break; + + case BPMSG_ERR: + log("remote report error: \"%s\"", bpi.ibuf+1); + gotoexit(PRC_ERROR); + break; + + case BPMSG_BSY: + log("remote busy error: \"%s\"", bpi.ibuf+1); + gotoexit(PRC_ERROR); + break; + + case BPMSG_GET: + if( binkp_parsfinfo(bpi.ibuf+1, &fname, &fsize, &ftime, &foffs) == 0 ) + { + if( send_file && !p_compfinfo(pi->send, fname, fsize, ftime) ) + { + if( fseek(pi->send->fp, foffs, SEEK_SET) == -1 ) + { + log("cannot send file from requested offset %ld", (long)foffs); + p_tx_fclose(pi); + send_file = FALSE; + } + else + { + log("sending \"%s\" from %ld offset", + pi->send->fname, (long)foffs); + pi->send->bytes_skipped = foffs; + pi->send->bytes_sent = foffs; + binkp_queuemsgf(&bpi, BPMSG_FILE, "%s %ld %ld %ld", + pi->send->net_name, (long)pi->send->bytes_total, + (long)pi->send->mod_time, (long)foffs); + } + } + } + break; + + default: + log("binkp got unhandled msg #%d", recv_rc); + break; + } + } /* end of while( !sent_EOB || !rcvd_EOB ) */ + +FinishSession: + if( binkp_flush_queue(&bpi, bpi.timeout) && rc == PRC_NOERROR ) + rc = PRC_ERROR; + +exit: + if( pi->send && pi->send->fp ) p_tx_fclose(pi); + if( pi->recv && pi->recv->fp ) p_rx_fclose(pi); + + binkp_deinit_bpinfo(&bpi); + + DEB((D_PROT, "binkp: BINKP exit = %d", rc)); + + return rc; +} + diff --git a/source/bforce/prot_binkp_api.c b/source/bforce/prot_binkp_api.c new file mode 100644 index 0000000..93c8bdf --- /dev/null +++ b/source/bforce/prot_binkp_api.c @@ -0,0 +1,283 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "version.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" +#include "session.h" +#include "prot_binkp.h" + +void binkp_init(s_handshake_protocol *THIS); +void binkp_deinit(s_handshake_protocol *THIS); +int binkp_incoming2(s_handshake_protocol *THIS); +int binkp_outgoing2(s_handshake_protocol *THIS); +s_faddr *binkp_remote_address(s_handshake_protocol *THIS); +char *binkp_remote_password(s_handshake_protocol *THIS); +char *binkp_remote_sysop_name(s_handshake_protocol *THIS); +char *binkp_remote_system_name(s_handshake_protocol *THIS); +char *binkp_remote_location(s_handshake_protocol *THIS); +char *binkp_remote_phone(s_handshake_protocol *THIS); +char *binkp_remote_flags(s_handshake_protocol *THIS); +char *binkp_remote_mailer(s_handshake_protocol *THIS); +s_faddr *binkp_local_address(s_handshake_protocol *THIS); +char *binkp_local_password(s_handshake_protocol *THIS); + +s_handshake_protocol handshake_protocol_binkp = { + /* Section 1 */ + "BinkP", + "", + "", + NULL, + NULL, + 0, + binkp_init, + binkp_deinit, + binkp_incoming2, + binkp_outgoing2, + /* Section 2 */ + binkp_remote_address, + binkp_remote_password, + binkp_remote_sysop_name, + binkp_remote_system_name, + binkp_remote_location, + binkp_remote_phone, + binkp_remote_flags, + binkp_remote_mailer, + NULL, + /* Section 3 */ + binkp_local_address, + binkp_local_password +}; + +void binkp_init(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data == NULL); + ASSERT(THIS->local_data == NULL); + + THIS->remote_data = (char *)xmalloc(sizeof(s_binkp_sysinfo)); + THIS->local_data = (char *)xmalloc(sizeof(s_binkp_sysinfo)); + THIS->protocol = PROT_BINKP; + + memset(THIS->remote_data, '\0', sizeof(s_binkp_sysinfo)); + memset(THIS->local_data, '\0', sizeof(s_binkp_sysinfo)); +} + +void binkp_deinit(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + ASSERT(THIS->local_data); + + if( THIS->remote_data ) + { + memset(THIS->remote_data, '\0', sizeof(s_binkp_sysinfo)); + free(THIS->remote_data); + } + + if( THIS->local_data ) + { + memset(THIS->local_data, '\0', sizeof(s_binkp_sysinfo)); + free(THIS->local_data); + } +} + +int binkp_incoming2(s_handshake_protocol *THIS) +{ + int rc = -1; + s_binkp_sysinfo *remote_data = NULL; + s_binkp_sysinfo *local_data = NULL; + + ASSERT(THIS); + ASSERT(THIS->remote_data); + ASSERT(THIS->local_data); + + remote_data = (s_binkp_sysinfo *)THIS->remote_data; + local_data = (s_binkp_sysinfo *)THIS->local_data; + + binkp_set_sysinfo(local_data, NULL, FALSE); + + rc = binkp_incoming(local_data, remote_data); + + binkp_log_sysinfo(remote_data); + if( remote_data->anum > 0 ) + { + session_remote_lookup(remote_data->addrs, remote_data->anum); + session_remote_log_status(); + } + + if( rc == HRC_OK ) + { + /* + * Create mail/files queue + */ + session_create_files_queue(remote_data->addrs, + remote_data->anum); + session_set_send_options(); + session_set_inbound(); + } + + return rc; +} + +int binkp_outgoing2(s_handshake_protocol *THIS) +{ + int rc = HRC_OTHER_ERR; + s_binkp_sysinfo *remote_data = NULL; + s_binkp_sysinfo *local_data = NULL; + + ASSERT(THIS); + ASSERT(THIS->remote_data); + ASSERT(THIS->local_data); + + remote_data = (s_binkp_sysinfo *)THIS->remote_data; + local_data = (s_binkp_sysinfo *)THIS->local_data; + + binkp_set_sysinfo(local_data, &state.node.addr, TRUE); + + rc = binkp_outgoing(local_data, remote_data); + + binkp_log_sysinfo(remote_data); + if( remote_data->anum > 0 ) + { + session_remote_lookup(remote_data->addrs, remote_data->anum); + session_remote_log_status(); + } + + if( rc == HRC_OK ) + { + /* + * Create mail/files queue + */ + session_create_files_queue(remote_data->addrs, + remote_data->anum); + session_set_send_options(); + session_set_inbound(); + } + + return rc; +} + +s_faddr *binkp_remote_address(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_binkp_sysinfo *)THIS->remote_data)->anum > 0 ) + return &((s_binkp_sysinfo *)THIS->remote_data)->addrs[0].addr; + + return NULL; +} + +char *binkp_remote_password(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_binkp_sysinfo *)THIS->remote_data)->passwd[0] ) + return ((s_binkp_sysinfo *)THIS->remote_data)->passwd; + + return NULL; +} + +char *binkp_remote_sysop_name(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_binkp_sysinfo *)THIS->remote_data)->sysop[0] ) + return ((s_binkp_sysinfo *)THIS->remote_data)->sysop; + + return NULL; +} + +char *binkp_remote_system_name(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_binkp_sysinfo *)THIS->remote_data)->systname[0] ) + return ((s_binkp_sysinfo *)THIS->remote_data)->systname; + + return NULL; +} + +char *binkp_remote_location(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_binkp_sysinfo *)THIS->remote_data)->location[0] ) + return ((s_binkp_sysinfo *)THIS->remote_data)->location; + + return NULL; +} + +char *binkp_remote_phone(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_binkp_sysinfo *)THIS->remote_data)->phone[0] ) + return ((s_binkp_sysinfo *)THIS->remote_data)->phone; + + return NULL; +} + +char *binkp_remote_flags(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_binkp_sysinfo *)THIS->remote_data)->flags[0] ) + return ((s_binkp_sysinfo *)THIS->remote_data)->flags; + + return NULL; +} + +char *binkp_remote_mailer(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_binkp_sysinfo *)THIS->remote_data)->progname[0] ) + return ((s_binkp_sysinfo *)THIS->remote_data)->progname; + + return NULL; +} + +s_faddr *binkp_local_address(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->local_data); + + if( ((s_binkp_sysinfo *)THIS->local_data)->anum > 0 ) + return &((s_binkp_sysinfo *)THIS->local_data)->addrs[0].addr; + + return NULL; +} + +char *binkp_local_password(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->local_data); + + if( ((s_binkp_sysinfo *)THIS->local_data)->passwd[0] ) + return ((s_binkp_sysinfo *)THIS->local_data)->passwd; + + return NULL; +} + diff --git a/source/bforce/prot_binkp_misc.c b/source/bforce/prot_binkp_misc.c new file mode 100644 index 0000000..f3f9242 --- /dev/null +++ b/source/bforce/prot_binkp_misc.c @@ -0,0 +1,740 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "io.h" +#include "session.h" +#include "outbound.h" +#include "prot_common.h" +#include "prot_binkp.h" + +/***************************************************************************** + * Initialise binkp state structure, allocate memory for buffers, etc. + * + * Arguments: + * bpi pointer to the binkp state structure (s_bpinfo) + * + * Return value: + * None + */ +void binkp_init_bpinfo(s_bpinfo *bpi) +{ + memset(bpi, '\0', sizeof(s_bpinfo)); + + bpi->obuf = (char*)xmalloc(BINKP_MAX_BLKSIZE + BINKP_BLK_HDRSIZE + 1); + bpi->opos = 0; + bpi->optr = bpi->obuf; + + bpi->inew = TRUE; + bpi->isize = -1; + bpi->ibuf = (char*)xmalloc(BINKP_MAX_BLKSIZE + BINKP_BLK_HDRSIZE + 1); + + bpi->timeout = conf_number(cf_binkp_timeout); + if( !bpi->timeout ) + bpi->timeout = 300; +} + +/***************************************************************************** + * DeInitialise binkp state structure, release allocated memory, etc. + * + * Arguments: + * bpi pointer to the binkp state structure (s_bpinfo) + * + * Return value: + * None + */ +void binkp_deinit_bpinfo(s_bpinfo *bpi) +{ + if( bpi->obuf ) + free(bpi->obuf); + if( bpi->ibuf ) + free(bpi->ibuf); + if( bpi->msgqueue ) + free(bpi->msgqueue); + + memset(bpi, '\0', sizeof(s_bpinfo)); +} + +/***************************************************************************** + * Fills s[0] and s[1] with binkp frame header using value of u + * + * Arguments: + * s pointer to the binkp's frame header (2 bytes) + * val value to put + * + * Return value: + * None + */ +void binkp_puthdr(char *s, unsigned int val) +{ + s[0] = ( (unsigned long) val >> 8 ) & 0xff; + s[1] = ( (unsigned long) val ) & 0xff; +} + +/***************************************************************************** + * Fills s[0] with binkp message type value + * + * Arguments: + * s pointer to the destination buffer + * msg message type + * + * Return value: + * None + */ +void binkp_putmsgtype(char *s, e_bpmsg msg) +{ + s[0] = ( (unsigned int) msg ) & 0xff; +} + +/***************************************************************************** + * Extract size from binkp frame header + * + * Arguments: + * s pointer to the source buffer + * + * Return value: + * Value, extracted from binkp header + */ +int binkp_gethdr(const char *s) +{ + return ( (unsigned int) (((unsigned char) s[0]) & 0x7f) << 8 ) + | ( (unsigned int) (((unsigned char) s[1]) & 0xff) ); +} + +/***************************************************************************** + * Extract message type from s[0] + * + * Arguments: + * s pointer to the source buffer (1 byte) + * + * Return value: + * Value, extracted from binkp header, or -1 if extracted message type is + * out of range + */ +int binkp_getmsgtype(char ch) +{ + int val = ( ((unsigned char)ch) & 0x7f ); + + if( BPMSG_MIN > val || val > BPMSG_MAX ) + return -1; + else + return val; +} + +/***************************************************************************** + * Puts a message to the output messages queue. These msgs will be send + * right after the current data block + * + * Arguments: + * bpi binkp state structure + * msg message type + * s1 message text + * s2 message text (will be concatenated with s1) + * + * Return value: + * None + */ +void binkp_queuemsg(s_bpinfo *bpi, e_bpmsg msg, const char *s1, const char *s2) +{ + bpi->msgqueue = xrealloc(bpi->msgqueue, sizeof(s_bpmsg)*(bpi->n_msgs + 1)); + memset(&bpi->msgqueue[bpi->n_msgs], '\0', sizeof(s_bpmsg)); + + /* Set message type */ + bpi->msgqueue[bpi->n_msgs].type = msg; + + /* Set message data size (without frame header) */ + bpi->msgqueue[bpi->n_msgs].size = 1; + if( s1 ) bpi->msgqueue[bpi->n_msgs].size += strlen(s1); + if( s2 ) bpi->msgqueue[bpi->n_msgs].size += strlen(s2); + + /* Set message data */ + bpi->msgqueue[bpi->n_msgs].data = xmalloc(bpi->msgqueue[bpi->n_msgs].size+3); + binkp_puthdr(bpi->msgqueue[bpi->n_msgs].data, + (unsigned)(bpi->msgqueue[bpi->n_msgs].size | 0x8000)); + + binkp_putmsgtype(bpi->msgqueue[bpi->n_msgs].data + 2, msg); + + bpi->msgqueue[bpi->n_msgs].data[3] = '\0'; + if( s1 ) strcat(bpi->msgqueue[bpi->n_msgs].data + 3, s1); + if( s2 ) strcat(bpi->msgqueue[bpi->n_msgs].data + 3, s2); + + DEB((D_PROT, "binkp_queuemsg: queued message #%d, %ld bytes, \"%s\"", + (int)bpi->msgqueue[bpi->n_msgs].type, + (long)bpi->msgqueue[bpi->n_msgs].size, + (char*)bpi->msgqueue[bpi->n_msgs].data+3)); + + ++bpi->n_msgs; +} + +/***************************************************************************** + * Sends a message using format string + * + * Arguments: + * bpi binkp state structure + * msg message type + * fmt pointer to the format string, (man printf) + * + * Return value: + * None + */ +void binkp_queuemsgf(s_bpinfo *bpi, e_bpmsg msg, const char *fmt, ...) +{ + char msg_text[2048]; + va_list ap; + + va_start(ap, fmt); +#ifdef HAVE_SNPRINTF + vsnprintf(msg_text, sizeof(msg_text), fmt, ap); +#else + vsprintf(msg_text, fmt, ap); +#endif + va_end(ap); + + binkp_queuemsg(bpi, msg, msg_text, NULL); +} + +/***************************************************************************** + * Parse most common message arguments, send error message to remote + * if needed. + * + * Arguments: + * s pointer to the string to parse + * fn pointer to the pointer for extracted file name + * sz pointer to the extracted file size + * tm pointer to the extracted file modification time + * offs pointer to the extracted file offset + * + * Return value: + * non-zero value on error, zero on success + */ +int binkp_parsfinfo(char *s, char **fn, size_t *sz, time_t *tm, size_t *offs) +{ + char *n; + char *p_fname = NULL; + char *p_size = NULL; + char *p_time = NULL; + char *p_offs = NULL; + + /* Attention, offs may be NULL! */ + + ASSERT(s != NULL && fn != NULL && sz != NULL && tm != NULL); + + DEB((D_PROT, "binkp_parsemsg: want parse \"%s\"", s)); + + p_fname = string_token(s, &n, NULL, 0); + p_size = string_token(NULL, &n, NULL, 0); + p_time = string_token(NULL, &n, NULL, 0); + if( offs ) p_offs = string_token(NULL, &n, NULL, 0); + + if( p_fname && p_size && p_time && (!offs || p_offs) ) + { + if( ISDEC(p_size) && ISDEC(p_time) && (!offs || ISDEC(p_offs)) ) + { + (*fn) = p_fname; + (*sz) = atol(p_size); + (*tm) = atol(p_time); + if( offs ) *offs = atol(p_offs); + DEB((D_PROT, "binkp_parsemsg: file = \"%s\", size = %d, time = %d", + *fn, *sz, *tm)); + return 0; + } + } + return 1; +} + +/***************************************************************************** + * Put message to a buffer + * + * Arguments: + * bpi binkp state structure + * msg message + * + * Return value: + * Zero on success, and non-zero value if no more free space left + * in the buffer + */ +int binkp_buffer_message(s_bpinfo *bpi, s_bpmsg *msg) +{ + DEB((D_PROT, "binkp_buffer_message: buffer message #%d, %ld byte(s)", + (int)msg->type, (long)msg->size)); + + /* Check for possible internal error */ + if( msg->size > BINKP_MAX_BLKSIZE ) + { + log("size of msg we want to send is too big (%db)", msg->size); + return 1; + } + + /* Is there space for the new msg? */ + if( bpi->opos + msg->size > BINKP_MAX_BLKSIZE ) return 1; + + if( msg->data ) + { + memcpy(bpi->obuf + bpi->opos, msg->data, msg->size + BINKP_BLK_HDRSIZE); + bpi->opos += msg->size + BINKP_BLK_HDRSIZE; + free(msg->data); + msg->data = NULL; + } + + return 0; +} + +/***************************************************************************** + * Send as much buffered data as possible (non-blocking) + * + * Arguments: + * bpi binkp state structure + * + * Return value: + * Zero on success, and non-zero value on errors + */ +int binkp_send_buffer(s_bpinfo *bpi) +{ + int n; + + DEB((D_PROT, "binkp_send_buffer: sending %ld byte(s)", (long)bpi->opos)); + + n = tty_write(bpi->optr, bpi->opos); + + if( n >= bpi->opos ) + { bpi->optr = bpi->obuf; bpi->opos = 0; } + else if( n > 0 ) + { bpi->optr += n; bpi->opos -= n; } + else + return -1; + + return 0; +} + +/***************************************************************************** + * Send as much buffered data or messages from the queue as possible + * + * Arguments: + * bpi binkp state structure + * + * Return value: + * Zero on success, and non-zero value on errors + */ +int binkp_send(s_bpinfo *bpi) +{ + int i; + + if( bpi->opos == 0 && bpi->msgqueue ) + { + /* + * Buffer is empty and there are unsent msgs + */ + for( i = 0; i < bpi->n_msgs; i++ ) + { + if( bpi->msgqueue[i].sent == FALSE ) + { + if( binkp_buffer_message(bpi, &bpi->msgqueue[i]) ) + break; + else + bpi->msgqueue[i].sent = TRUE; + } + } + /* If the message queue is empty, free it */ + if( i >= bpi->n_msgs ) + { + if( bpi->msgqueue ) + { free(bpi->msgqueue); bpi->msgqueue = NULL; } + bpi->n_msgs = 0; + } + } + + return bpi->opos ? binkp_send_buffer(bpi) : 0; +} + +/***************************************************************************** + * Flush all buffers and queues that can contain unsent data + * + * Arguments: + * bpi binkp state structure + * timeout abort flushing if this time will be exceeded + * + * Return value: + * Zero on success, and non-zero value on errors + */ +int binkp_flush_queue(s_bpinfo *bpi, int timeout) +{ + bool send_ready = FALSE; + time_t flush_timer; + + timer_set(&flush_timer, timeout); + + while( bpi->opos > 0 || bpi->n_msgs > 0 ) + { + if( timer_expired(flush_timer) + || tty_select(NULL, &send_ready, 10) < 0 ) + return -1; + + if( send_ready && binkp_send(bpi) < 0 ) + return -1; + } + + return 0; +} + +/***************************************************************************** + * Try to receive next message or data block in non-blocking mode + * + * Arguments: + * bpi binkp state structure + * + * Return value: + * One of the BPMSG_* values + */ +int binkp_recv(s_bpinfo *bpi) +{ + int n = 0; + int size; + + if( bpi->inew || bpi->isize == -1 ) + { + bpi->inew = FALSE; + bpi->isize = -1; + size = BINKP_BLK_HDRSIZE; + } + else + size = bpi->isize; + + if( size > 0 ) + { + n = tty_read(bpi->ibuf + bpi->ipos, size - bpi->ipos); + if( n <= 0 ) return BPMSG_EXIT; + } + + bpi->ipos += n; + + if( bpi->ipos == size ) + { + if( bpi->isize == -1 ) + { + /* We got block header */ + bpi->ipos = 0; + bpi->imsg = ((bpi->ibuf[0] >> 7) & 0377) ? TRUE : FALSE; + bpi->isize = binkp_gethdr(bpi->ibuf); + DEB((D_PROT, "binkp_recv: received header: %ld byte(s) (%s)", + (long)bpi->isize, bpi->imsg ? "msg" : "data")); + if( bpi->isize > BINKP_MAX_BLKSIZE ) + { + log("internal error: got %ld bytes block size", bpi->isize); + return BPMSG_EXIT; + } + else if( bpi->isize == 0 ) + { + bpi->ipos = 0; + bpi->inew = TRUE; + bpi->isize = -1; + if( bpi->imsg == TRUE ) + log("zero length message from remote"); + } + } + else /* We got whole data block/message */ + { + if( bpi->imsg == TRUE ) /* Is it message? */ + { + bpi->ipos = 0; + bpi->inew = TRUE; + bpi->ibuf[size] = '\0'; + bpi->imsgtype = binkp_getmsgtype(bpi->ibuf[0]); + DEB((D_PROT, "binkp_recv: got message #%d, %ld byte(s), \"%s\"", + (int)bpi->imsgtype, bpi->isize, bpi->ibuf+1)); + if( bpi->imsgtype < 0 ) + { + bpi->isize = -1; + log("got incorrect message type"); + if( ++bpi->junkcount >= 5 ) + { + log("junk count exceeded"); + return BPMSG_EXIT; + } + return BPMSG_NONE; + } + return bpi->imsgtype; + } + else /* It is data */ + { + bpi->ipos = 0; + bpi->inew = TRUE; + bpi->ibuf[size] = '\0'; + DEB((D_PROT, "binkp_recv: got data block, %ld byte(s)", + (long)bpi->isize)); + return BPMSG_DATA; + } + } + } + + return BPMSG_NONE; +} + +/***************************************************************************** + * Send (queue) system information to the remote + * + * Arguments: + * bpi binkp state structure + * binkp structure with the system information + * + * Return value: + * None + */ +void binkp_queue_sysinfo(s_bpinfo *bpi, s_binkp_sysinfo *binkp) +{ + int i; + char *astr = NULL; + char abuf[BF_MAXADDRSTR+1]; + + if( !state.caller && binkp->challenge_length > 0 ) + { + char challenge[128]; + string_bin_to_hex(challenge, binkp->challenge, binkp->challenge_length); + binkp_queuemsgf(bpi, BPMSG_NUL, "OPT CRAM-MD5-%s", challenge); + } + + binkp_queuemsg(bpi, BPMSG_NUL, "SYS ", binkp->systname); + binkp_queuemsg(bpi, BPMSG_NUL, "ZYZ ", binkp->sysop); + binkp_queuemsg(bpi, BPMSG_NUL, "LOC ", binkp->location); + binkp_queuemsg(bpi, BPMSG_NUL, "PHN ", binkp->phone); + binkp_queuemsg(bpi, BPMSG_NUL, "NDL ", binkp->flags); + + binkp_queuemsg(bpi, BPMSG_NUL, "TIME ", binkp->timestr); + + binkp_queuemsgf(bpi, BPMSG_NUL, "VER %s %s/%d.%d", + binkp->progname, binkp->protname, + binkp->majorver, binkp->minorver); + + for( i = 0; i < binkp->anum; i++ ) + { + if( i ) astr = xstrcat(astr, " "); + astr = xstrcat(astr, ftn_addrstr(abuf, binkp->addrs[i].addr)); + } + + if( astr ) + { + binkp_queuemsg(bpi, BPMSG_ADR, NULL, astr); + free(astr); + } +} + +/***************************************************************************** + * Write system information to the log + * + * Arguments: + * binkp structure with the system information + * + * Return value: + * None + */ +void binkp_log_sysinfo(s_binkp_sysinfo *binkp) +{ + int i; + char abuf[BF_MAXADDRSTR+1]; + + if( binkp->anum ) + for( i = 0; i < binkp->anum; i++ ) + { + log(" Address : %s", ftn_addrstr(abuf, binkp->addrs[i].addr)); + } + + if( *binkp->systname && *binkp->phone ) + log(" System : %s (%s)", + string_printable(binkp->systname), + string_printable(binkp->phone)); + else if( *binkp->systname ) + log(" System : %s", + string_printable(binkp->systname)); + else if( *binkp->phone ) + log(" Phone : %s", + string_printable(binkp->phone)); + +#ifdef BFORCE_LOG_PASSWD + if( *binkp->passwd ) + log(" Password : %s", string_printable(binkp->passwd)); +#endif + + if( *binkp->opt ) + log(" Options : %s", string_printable(binkp->opt)); + + if( *binkp->sysop && *binkp->location ) + log(" SysOp : %s from %s", + string_printable(binkp->sysop), + string_printable(binkp->location)); + else if( *binkp->sysop ) + log(" SysOp : %s", + string_printable(binkp->sysop)); + else if( *binkp->location ) + log(" Location : %s", + string_printable(binkp->location)); + + if( *binkp->progname ) + { + log(" Mailer : %s (%s/%d.%d)", + *binkp->progname ? string_printable(binkp->progname) : "?", + *binkp->protname ? string_printable(binkp->protname) : "?", + binkp->majorver, binkp->minorver); + } + if( *binkp->flags ) + log(" Flags : %s", string_printable(binkp->flags)); + if( *binkp->timestr ) + log(" Time : %s", string_printable(binkp->timestr)); +} + +/***************************************************************************** + * Set our local system information + * + * Arguments: + * binkp structure where to store system information + * remote_addr remote main address (for setting best AKA) + * caller are we calling system? + * + * Return value: + * None + */ +void binkp_set_sysinfo(s_binkp_sysinfo *binkp, s_faddr *remote_addr, bool caller) +{ + s_cval_entry *addr_ptr; + s_cval_entry *hide_ptr; + s_faddr *primary = NULL; + + const char *p_systname = conf_string(cf_system_name); + const char *p_location = conf_string(cf_location); + const char *p_sysop = conf_string(cf_sysop_name); + const char *p_phone = conf_string(cf_phone); + const char *p_flags = conf_string(cf_flags); + + /* free previously allocated memory */ + if( binkp->addrs ) + free(binkp->addrs); + + memset(binkp, '\0', sizeof(s_binkp_sysinfo)); + + /* Set best primary address */ + if( remote_addr ) + { + primary = session_get_bestaka(*remote_addr); + + /* Add primary address */ + if( primary ) + session_addrs_add(&binkp->addrs, &binkp->anum, *primary); + } + + /* Add other AKAs */ + for( addr_ptr = conf_first(cf_address); addr_ptr; + addr_ptr = conf_next(addr_ptr) ) + { + for( hide_ptr = conf_first(cf_hide_our_aka); hide_ptr; + hide_ptr = conf_next(hide_ptr) ) + { + if( !ftn_addrcomp(hide_ptr->d.falist.addr, addr_ptr->d.falist.addr) ) + break; + } + + if( !hide_ptr && primary != &addr_ptr->d.falist.addr ) + session_addrs_add(&binkp->addrs, &binkp->anum, + addr_ptr->d.falist.addr); + } + + if( binkp->anum == 0 ) + log("warning: no addresses will be presented to remote"); + + /* session password */ + if( caller ) + session_get_password(state.node.addr, binkp->passwd, sizeof(binkp->passwd)); + + binkp->majorver = BINKP_MAJOR; + binkp->minorver = BINKP_MINOR; + + strnxcpy(binkp->progname, BF_NAME"/"BF_VERSION"/"BF_OS, sizeof(binkp->progname)); + strnxcpy(binkp->protname, BINKP_NAME, sizeof(binkp->protname)); + + strnxcpy(binkp->sysop, p_sysop ? p_sysop : "Unknown", sizeof(binkp->sysop)); + strnxcpy(binkp->systname, p_systname ? p_systname : "Unknown", sizeof(binkp->systname)); + strnxcpy(binkp->location, p_location ? p_location : "Unknown", sizeof(binkp->location)); + strnxcpy(binkp->phone, p_phone ? p_phone : "Unknown", sizeof(binkp->phone)); + strnxcpy(binkp->flags, p_flags ? p_flags : "BINKP", sizeof(binkp->flags)); + + time_string_format(binkp->timestr, sizeof(binkp->timestr), "%Y/%m/%d %H:%M:%S", 0); + + /* Set session challenge string */ + if( !caller ) + { + long rnd = (long)random(); + int pid = ((int)getpid()) ^ ((int)random()); + long utm = (long)time(0); + + binkp->options |= BINKP_OPT_MD5; + binkp->challenge[0] = (unsigned char)(rnd ); + binkp->challenge[1] = (unsigned char)(rnd >> 8 ); + binkp->challenge[2] = (unsigned char)(rnd >> 16); + binkp->challenge[3] = (unsigned char)(rnd >> 24); + binkp->challenge[4] = (unsigned char)(pid ); + binkp->challenge[5] = (unsigned char)(pid >> 8 ); + binkp->challenge[6] = (unsigned char)(utm ); + binkp->challenge[7] = (unsigned char)(utm >> 8 ); + binkp->challenge[8] = (unsigned char)(utm >> 16); + binkp->challenge[9] = (unsigned char)(utm >> 24); + + binkp->challenge_length = 10; + } +} + +void binkp_parse_options(s_binkp_sysinfo *binkp, char *options) +{ + char *p, *n; + + for( p = string_token(options, &n, NULL, 0); p; + p = string_token(NULL, &n, NULL, 0) ) + { + if( !strcmp(p, "NR") ) + binkp->options |= BINKP_OPT_NR; + else if( !strcmp(p, "MB") ) + binkp->options |= BINKP_OPT_MB; + else if( !strcmp(p, "MPWD") ) + binkp->options |= BINKP_OPT_MPWD; + else if( !strncmp(p, "CRAM-", 5) ) + { + char *hash_types = p + 5; + char *challenge = strchr(hash_types, '-'); + + if( challenge ) + { + char *pp, *nn; + + *challenge++ = '\0'; + for( pp = string_token(hash_types, &nn, "/", 0); pp; + pp = string_token(NULL, &nn, "/", 0) ) + { + if( !strcmp(pp, "SHA1") ) + binkp->options |= BINKP_OPT_SHA1; + else if( !strcmp(pp, "MD5") ) + binkp->options |= BINKP_OPT_MD5; + else if( !strcmp(pp, "DES") ) + binkp->options |= BINKP_OPT_DES; + } + + if( strlen(challenge) > (2*sizeof(binkp->challenge)) ) + log("binkp got too long challenge string"); + else + binkp->challenge_length = string_hex_to_bin( + binkp->challenge, challenge); + } + else + log("binkp got invalid option: \"%s\"", string_printable(p)); + } + } +} + diff --git a/source/bforce/prot_common.c b/source/bforce/prot_common.c new file mode 100644 index 0000000..8347d59 --- /dev/null +++ b/source/bforce/prot_common.c @@ -0,0 +1,1559 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "io.h" +#include "util.h" +#include "session.h" +#include "prot_common.h" +#include "outbound.h" +#include "freq.h" + +const char *Protocols[] = +{ + "Unknown", "Xmodem", "Zmodem", "ZedZap", "DirZap", + "Janus", "Hydra", "Tcp", "BinkP" +}; + +/***************************************************************************** + * Get first file from files queue not marked as sent. Extract files in the + * order: netmail, arcmail, other files, file request. Files of equal type + * extract in the order of flavor descending + * + * Arguments: + * dest pointer to the pointer to put file information to + * pi pointer to the protocol information structure + * q pointer to the files queue + * + * Return value: + * Zero value on success and non-zero if nothing to send + */ +static int prot_get_next_file(s_filelist **dest, s_protinfo *pi, s_fsqueue *q) +{ + s_filelist *ptrl = NULL; + s_filelist *best = NULL; + + *dest = NULL; + + for( ptrl = q->fslist; ptrl; ptrl = ptrl->next ) + if( ptrl->status == STATUS_WILLSEND ) + { + if( pi->reqs_only ) + { + if( (ptrl->type & TYPE_REQUEST) ) + { + *dest = ptrl; + return 0; + } + } + else if( best ) + { + if( (ptrl->type & TYPE_NETMAIL) ) + { + if( (best->type & TYPE_NETMAIL) ) + { + if( ptrl->flavor > best->flavor ) + best = ptrl; + } else + best = ptrl; + } + else if( (ptrl->type & TYPE_ARCMAIL) ) + { + if( (best->type & TYPE_ARCMAIL) && (ptrl->flavor > best->flavor) ) + best = ptrl; + else if( !(best->type & TYPE_NETMAIL) + && !(best->type & TYPE_ARCMAIL) ) + best = ptrl; + } + else if( !(ptrl->type & TYPE_REQUEST) && (best->type & TYPE_REQUEST) ) + best = ptrl; + } + else + best = ptrl; + } + + if( best ) + { + *dest = best; + return 0; + } + + for( ptrl = pi->filelist; ptrl; ptrl = ptrl->next ) + if( ptrl->status == STATUS_WILLSEND ) + { + *dest = ptrl; + return 0; + } + + return 1; +} + +/***************************************************************************** + * Calculate total files number and size we are going to send. It will be + * used by some protocols that supports reporting of total traffic to the + * remote side (e.g. Zmodem protocols could) + * + * Arguments: + * pi pointer to the protocol information structure + * q pointer to the files queue + * + * Return value: + * None + */ +/* +void prot_update_traffic(s_protinfo *pi, const s_fsqueue *q) +{ + s_filelist *ptrl = NULL; + + pi->send_bytesleft = 0; + pi->send_filesleft = 0; + + if( !state.sopts.holdall ) + { + for( ptrl = q->fslist; ptrl; ptrl = ptrl->next ) + if( ptrl->status == STATUS_WILLSEND ) + { + pi->send_filesleft += 1; + pi->send_bytesleft += ptrl->size; + } + + for( ptrl = pi->filelist; ptrl; ptrl = ptrl->next ) + if( ptrl->status == STATUS_WILLSEND ) + { + pi->send_filesleft += 1; + pi->send_bytesleft += ptrl->size; + } + } +} +*/ + +/***************************************************************************** + * Open next file for sending. Set all necessary information. And do all + * necessary checks. + * + * Arguments: + * pi pointer to the protocol information structure + * + * Return value: + * Zero value on success and non-zero if have nothing to send + */ +int p_tx_fopen(s_protinfo *pi) +{ + FILE *fp; + struct stat st; + s_filelist *ptrl = NULL; + + if( state.sopts.holdall ) + return 1; + +get_next_file: + if( prot_get_next_file(&ptrl, pi, &state.queue) || !ptrl ) + return 1; + + /* Mark this file as "processed" */ + ptrl->status = STATUS_SENDING; + + pi->send_left_num -= 1; + pi->send_left_size -= ptrl->size; + + if( pi->send_left_size < 0 ) + pi->send_left_size = 0; + if( pi->send_left_num < 0 ) + pi->send_left_num = 0; + + /* Reset MinCPS time counter */ + pi->tx_low_cps_time = 0; + + DEB((D_PROT, "p_tx_fopen: now opening \"%s\"", ptrl->fname)); + + if( stat(ptrl->fname, &st) ) + { + logerr("send: cannot stat file \"%s\"", ptrl->fname); + goto get_next_file; + } + + if( (fp = file_open(ptrl->fname, "r")) == NULL ) + { + logerr("send: cannot open file \"%s\"", ptrl->fname); + goto get_next_file; + } + + /* + * Add new entry to the send files queue + */ + if( pi->sentfiles && pi->n_sentfiles > 0 ) + { + pi->sentfiles = (s_finfo *)xrealloc(pi->sentfiles, sizeof(s_finfo)*(pi->n_sentfiles+1)); + memset(&pi->sentfiles[pi->n_sentfiles], '\0', sizeof(s_finfo)); + pi->send = &pi->sentfiles[pi->n_sentfiles++]; + } + else + { + pi->sentfiles = (s_finfo *)xmalloc(sizeof(s_finfo)); + memset(pi->sentfiles, '\0', sizeof(s_finfo)); + pi->send = pi->sentfiles; + pi->n_sentfiles = 1; + } + + /* + * Set file information + */ + pi->send->fp = fp; + pi->send->local_name = (char*)xstrcpy(file_getname(ptrl->fname)); + pi->send->net_name = recode_file_out(p_convfilename(pi->send->local_name, ptrl->type)); + pi->send->fname = (char*)xstrcpy(ptrl->fname); + pi->send->mod_time = (ptrl->type & TYPE_REQUEST) ? time(NULL) : st.st_mtime; + pi->send->mod_time = localtogmt(pi->send->mod_time); + pi->send->mod_time += pi->send->mod_time%2; + pi->send->mode = st.st_mode; + pi->send->bytes_total = st.st_size; + pi->send->start_time = time(NULL); + pi->send->eofseen = FALSE; + pi->send->status = FSTAT_PROCESS; + pi->send->type = ptrl->type; + pi->send->action = ptrl->action; + pi->send->flodsc = ptrl->flodsc; + + if( strcmp(pi->send->local_name, pi->send->net_name) == 0 ) + { + log("send: \"%s\" %d bytes", + pi->send->local_name, + pi->send->bytes_total); + } + else + { + log("send: \"%s\" %d bytes -> \"%s\"", + pi->send->local_name, + pi->send->bytes_total, + pi->send->net_name); + } + + return 0; +} + +void prot_traffic_update(s_traffic *traf, size_t size, int xtime, int type) +{ + if( type & TYPE_REQANSW ) + { + traf->freqed_size += size; + traf->freqed_time += xtime; + traf->freqed_num++; + } + else if( type & TYPE_NETMAIL ) + { + traf->netmail_size += size; + traf->netmail_time += xtime; + traf->netmail_num++; + } + else if( type & TYPE_ARCMAIL ) + { + traf->arcmail_size += size; + traf->arcmail_time += xtime; + traf->arcmail_num++; + } + else + { + traf->files_size += size; + traf->files_time += xtime; + traf->files_num++; + } +} + +size_t prot_traffic_total_size(const s_traffic *traff) +{ + return traff->netmail_size + traff->arcmail_size + + traff->files_size + traff->freqed_size; +} + +int prot_traffic_total_num(const s_traffic *traff) +{ + return traff->netmail_num + traff->arcmail_num + + traff->files_num + traff->freqed_num; +} + +/***************************************************************************** + * Close sending file. If file was sent successfully than make appropriate + * actions (e.g. unlink/truncate file) + * + * Arguments: + * pi pointer to the protocol information structure + * + * Return value: + * Zero value on success and non-zero to indicate error + */ +int p_tx_fclose(s_protinfo *pi) +{ + long trans_time = 0; + long cps = 0; + + if( pi->send->fp ) + { + (void)file_close(pi->send->fp); + pi->send->fp = NULL; + } + + /* + * Calculate send time, CPS, etc + */ + trans_time = (long)time(NULL) - (long)pi->send->start_time; + + if( trans_time > 0 ) + cps = (long)((pi->send->bytes_sent - pi->send->bytes_skipped) / trans_time); + + log("sent: \"%s\" %ld [%s]: %ld seconds, %ld CPS", + pi->send->net_name, + (long)(pi->send->bytes_sent - pi->send->bytes_skipped), + (pi->send->status == FSTAT_SKIPPED) ? "skipped" : + (pi->send->status == FSTAT_REFUSED) ? "refused" : + (pi->send->status == FSTAT_SUCCESS) ? "ok" : "error", + (long)(trans_time > 0) ? trans_time : 0, + (long)(cps > 0) ? cps : 0); + + /* + * Update outgoing traffic structure + */ + prot_traffic_update(&pi->traffic_sent, + pi->send->bytes_sent - pi->send->bytes_skipped, + trans_time, pi->send->type); + + /* + * Calculate time of sending FREQ'ed files + */ + if( (pi->send->type & TYPE_REQANSW) == TYPE_REQANSW ) + pi->send_freqtime += trans_time; + + /* + * Do necessary actions + */ + if( pi->send->status == FSTAT_SUCCESS || pi->send->status == FSTAT_SKIPPED ) + { + FILE *tfp; + + if( (pi->send->type & TYPE_FROMFLO) ) + out_flo_marksent(pi->send->fname, + state.queue.flotab[pi->send->flodsc].fname); + + switch(pi->send->action) { + case ACTION_NOTHING: + DEB((D_PROT, "p_tx_fclose: do nothing with file \"%s\"", pi->send->fname)); + break; + + case ACTION_UNLINK: + case ACTION_FORCEUNLINK: + DEB((D_PROT, "p_tx_fclose: unlinking file \"%s\"", pi->send->fname)); + if( unlink(pi->send->fname) && errno != ENOENT ) + logerr("send: cannot unlink file \"%s\"", pi->send->fname); + break; + + case ACTION_TRUNCATE: + DEB((D_PROT, "p_tx_fclose: truncating file \"%s\"", pi->send->fname)); + if( (tfp = fopen(pi->send->fname, "w")) ) + fclose(tfp); + else if( errno != ENOENT ) + logerr("send: cannot truncate file \"%s\"", pi->send->fname); + break; + } + } + + return 0; +} + +/***************************************************************************** + * Read next part of file to the buffer. User by transmitter. + * + * Arguments: + * buffer pointer to the buffer + * buflen buffer size + * pi pointer to the protocol information structure + * + * Return value: + * >= 0 - number of bytes read + * -1 - error reading file (must try to send file later) + * -2 - file must be skipped (send never) + */ +int p_tx_readfile(char *buffer, size_t buflen, s_protinfo *pi) +{ + int n; + struct stat st; + long ftell_pos = ftell(pi->send->fp); + + pi->send->eofseen = FALSE; /* clear EOF flag */ + + /* + * Sanity check: sync our transmitter position + * with the position returned by the ftell() + */ + if( ftell_pos < 0 ) + { + log("Error: ftell() return %ld for the file \"%s\"", + ftell_pos, pi->send->fname); + pi->send->status = FSTAT_REFUSED; + return -1; + } + + /* + * Try receive file later, if such error occurs + */ + if( pi->send->bytes_sent != ftell_pos ) + { + log("internal error: invalid transmitting offset"); + log("pi->send->bytes_sent = %ld, ftell() = %ld", + (long)pi->send->bytes_sent, ftell_pos); + pi->send->bytes_received = ftell_pos; + return -1; + } + + if( stat(pi->send->fname, &st) == -1 && errno == ENOENT ) + { + log("send: file not found! do you want to skip it?"); + pi->send->status = FSTAT_SKIPPED; + return -2; + } + else if( (n = fread(buffer, 1, buflen, pi->send->fp)) < buflen ) + { + if( feof(pi->send->fp) ) + pi->send->eofseen = TRUE; + else + { + log("send: error reading file from disk (ferror = %d)", + ferror(pi->send->fp)); + pi->send->status = FSTAT_REFUSED; + return -1; + } + } + + return n; +} + +/***************************************************************************** + * Write buffer to the file. Used by receiver. + * + * Arguments: + * buffer pointer to the buffer + * buflen number of bytes in buffer + * pi pointer to the protocol information structure + * + * Return value: + * 0 - successfully written + * -1 - error writing file (receive later) + * -2 - file must be skipped (receive never) + */ +int p_rx_writefile(const char *buffer, size_t buflen, s_protinfo *pi) +{ + struct stat st; + long ftell_pos = ftell(pi->recv->fp); + + /* + * Sanity check: sync our receiver position + * with the position returned by the ftell() + */ + if( ftell_pos < 0 ) + { + log("Error: ftell() return %ld for the file \"%s\"", + ftell_pos, pi->recv->fname); + pi->recv->status = FSTAT_REFUSED; + return -1; + } + + /* + * Try receive file later, if such error occurs + */ + if( pi->recv->bytes_received != ftell_pos ) + { + log("internal error: invalid receiving offset"); + log("pi->recv->bytes_received = %ld, ftell() = %ld", + (long)pi->recv->bytes_received, ftell_pos); + pi->recv->bytes_received = ftell_pos; + return -1; + } + + if( stat(pi->recv->fname, &st) == -1 ) + { + fflush(pi->recv->fp); + if( stat(pi->recv->fname, &st) == -1 && errno == ENOENT ) + { + log("recv: skip file \"%s\" (file not found)", pi->recv->fname); + pi->recv->status = FSTAT_SKIPPED; + return -2; + } + } + + if( buflen > 0 && fwrite(buffer, buflen, 1, pi->recv->fp) != 1 ) + { + log("recv: error writing file \"%s\" to disk (ferror = %d)", + pi->recv->fname, ferror(pi->recv->fp)); + pi->recv->status = FSTAT_REFUSED; + return -1; + } + + return 0; +} + +/***************************************************************************** + * Move file from temporary inbound to main + * + * Arguments: + * pi pointer to the protocol information structure + * + * Return value: + * 0 - successfully processed file + * 1 - error occured (mailer must refuse this file (receive later)) + */ +static int p_move2inbound(s_protinfo *pi) +{ + int rc = 0; + char *realname = NULL; + char *uniqname = NULL; + char *destname = NULL; + + if( state.inbound && pi->recv->local_name ) + { + realname = (char *)xstrcpy(state.inbound); + realname = (char *)xstrcat(realname, pi->recv->local_name); + } else + return 1; + + if( access(realname, F_OK) == -1 ) + { + destname = realname; + } + else + { + if( (uniqname = prot_unique_name(state.inbound, + pi->recv->local_name, pi->recv->type)) == NULL ) + { + log("recv: cannot get unique name for \"%s\"", + pi->recv->local_name); + free(realname); + return 1; + } + + if( !strcmp(realname, uniqname) ) + { + log("recv: overwriting \"%s\"", + file_getname(uniqname)); + } + else + { + log("recv: rename \"%s\" -> \"%s\"", + pi->recv->local_name, file_getname(uniqname)); + } + + destname = uniqname; + } + + if( (rc = rename(pi->recv->fname, destname)) == -1 ) + { + logerr("recv: cannot rename \"%s\" -> \"%s\"", + pi->recv->fname, destname); + } + else + { + mode_t fmode = 0; + + /* + * Change new file permissions + */ + if( (pi->recv->type & TYPE_NETMAIL) == TYPE_NETMAIL ) + fmode = conf_filemode(cf_mode_netmail); + else if( (pi->recv->type & TYPE_ARCMAIL) == TYPE_ARCMAIL ) + fmode = conf_filemode(cf_mode_arcmail); + else if( (pi->recv->type & TYPE_REQUEST) == TYPE_REQUEST ) + fmode = conf_filemode(cf_mode_request); + else if( (pi->recv->type & TYPE_TICFILE) == TYPE_TICFILE ) + fmode = conf_filemode(cf_mode_ticfile); + + if( fmode == 0 ) + fmode = conf_filemode(cf_mode_default); + + if( chmod(destname, fmode ? fmode : (S_IRUSR|S_IWUSR)) == -1 ) + logerr("recv: cannot set permissions for file \"%s\"", + destname); + } + + if( realname ) + free(realname); + if( uniqname ) + free(uniqname); + + return rc ? 1 : 0; +} + +/***************************************************************************** + * Compare the two file informations. One specified by file information + * structure (s_finfo) and another specified by other variables. + * + * Arguments: + * finf pointer to the file information + * fn file name + * sz file size + * tm file modification time + * + * Return value: + * Zero value if two files with such parameters seems to be the same + * file, and non-zero if it is different files + */ +int p_compfinfo(s_finfo *finf, const char *fn, size_t sz, time_t tm) +{ + return ( sz == finf->bytes_total && tm == finf->mod_time + && strcmp(fn, finf->net_name) == 0 ) ? 0 : 1; +} + +/***************************************************************************** + * Open file for receiving. If file with such name allready exist: + * 1) if timestamp and size identical to existing one, then skip; + * 2) if only timestamp is equal and size of existing file is shorter then + * it possible was an unfinished transfer - try to recover; + * 3) in all other cases rename receiving file. + * + * Arguments: + * pi pointer to the protocol information structure + * fn file name | + * sz file size | \ as it was reported by + * tm file last modification time | / remote side (need checks) + * mode file permissions | + * + * Return value: + * 0 - successful call + * 1 - refuse this file (receive later) + * 2 - skip this file (never receive it) + */ +int p_rx_fopen(s_protinfo *pi, char *fn, size_t sz, time_t tm, mode_t mode) +{ + const char *openmode = "w"; /* Set open mode to overwrite */ + struct stat st; + const char *p_skiplist = NULL; + const char *p_delaylist = NULL; + size_t minfree = 0; + size_t needed_bytes_total = 0; + + /* + * Check. May be we are receiving this file allready + */ + if( pi->recv && p_compfinfo(pi->recv, fn, sz, tm) == 0 ) + { + log("recv: got duplicated file information"); + + if( pi->recv->fp ) + return 0; + else if( pi->recv->status == FSTAT_SKIPPED ) + return 2; + else if( pi->recv->status == FSTAT_REFUSED ) + return 1; + } + + /* Reset mincps time counter */ + pi->rx_low_cps_time = 0; + + /* + * Add new entry to the receive files queue + */ + if( pi->rcvdfiles && pi->n_rcvdfiles > 0 ) + { + pi->rcvdfiles = (s_finfo *)xrealloc(pi->rcvdfiles, sizeof(s_finfo)*(pi->n_rcvdfiles+1)); + memset(&pi->rcvdfiles[pi->n_rcvdfiles], '\0', sizeof(s_finfo)); + pi->recv = &pi->rcvdfiles[pi->n_rcvdfiles++]; + } + else + { + pi->rcvdfiles = (s_finfo *)xmalloc(sizeof(s_finfo)); + memset(pi->rcvdfiles, '\0', sizeof(s_finfo)); + pi->recv = pi->rcvdfiles; + pi->n_rcvdfiles = 1; + } + + /* + * Set file information + */ + pi->recv->net_name = (char*)xstrcpy(fn); + pi->recv->local_name = xstrcpy(file_getname(fn)); + pi->recv->bytes_total = sz; + pi->recv->mod_time = tm; + pi->recv->mode = mode; + pi->recv->start_time = time(NULL); + pi->recv->eofseen = FALSE; + pi->recv->status = FSTAT_PROCESS; + pi->recv->type = out_filetype(pi->recv->net_name); + pi->recv->action = ACTION_NOTHING; + pi->recv->flodsc = 0; + + /* + * Convert file name to local charset + */ + recode_file_in(pi->recv->local_name); + + /* + * Remove undesirable characters from file name + */ + file_name_makesafe(pi->recv->local_name); + + /* + * Upper case file names convert to lower case. + */ + if( string_isupper(pi->recv->local_name) ) + string_tolower(pi->recv->local_name); + + if( strcmp(pi->recv->local_name, pi->recv->net_name) ) + { + log("recv: \"%s\" %d bytes -> \"%s\"", + string_printable(pi->recv->net_name), + pi->recv->bytes_total, + string_printable(pi->recv->local_name)); + } + else + { + log("recv: \"%s\" %d bytes", + string_printable(pi->recv->local_name), + pi->recv->bytes_total); + } + + /* + * Get `DelayFilesIn', `Skipfiles' and `MinFree' values + */ + p_skiplist = conf_string(cf_skip_files_recv); + p_delaylist = conf_string(cf_delay_files_recv); + minfree = conf_number(cf_min_free_space); + + /* + * Should we delay(refuse) this file NOW? + */ + if( p_delaylist && !checkmasks(p_delaylist, pi->recv->net_name) ) + { + log("recv: file from delaylist -> refuse"); + pi->recv->status = FSTAT_REFUSED; + return(1); + } + + /* + * Should we skip this file NOW? + */ + if( p_skiplist && !checkmasks(p_skiplist, pi->recv->net_name) ) + { + log("recv: file from skiplist -> skip"); + pi->recv->status = FSTAT_SKIPPED; + return(2); + } + + /* + * Check. May be we allready have this file + */ + if( (pi->recv->type & TYPE_REQUEST) || (pi->recv->type & TYPE_NETMAIL) ) + { + pi->recv->fname = p_gettmpname(state.tinbound, pi->recv->local_name, + state.node.addr, pi->recv->bytes_total, + pi->recv->mod_time); + } + else /* It is not netmail or filerequest */ + { + char *fname; + fname = (char *)xstrcpy(state.inbound); + fname = (char *)xstrcat(fname, pi->recv->local_name); + + if( stat(fname, &st ) == 0 ) + { + /* Skip file if we allready have it's copy */ + if( pi->recv->mod_time == localtogmt(st.st_mtime) + && pi->recv->bytes_total == st.st_size ) + { + log("recv: allready have \"%s\"", fname); + pi->recv->status = FSTAT_SKIPPED; + } + } + + free(fname); fname = NULL; + + if( pi->recv->status == FSTAT_SKIPPED ) + return 2; + + pi->recv->fname = p_gettmpname(state.tinbound, pi->recv->local_name, + state.node.addr, pi->recv->bytes_total, + pi->recv->mod_time); + + /* Now make same check for temporary inbound */ + if( stat(pi->recv->fname, &st) == 0 ) + { + /* Skip if it is the same file */ + if( pi->recv->mod_time == localtogmt(st.st_mtime) + && pi->recv->bytes_total == st.st_size ) + { + /* + * We will skip it and try to move it into inbound + * directory, do you know who could left it here ? :) + */ + + log("recv: allready have \"%s\"", pi->recv->fname); + + if( p_move2inbound(pi) == 0 ) + pi->recv->status = FSTAT_SKIPPED; + else + pi->recv->status = FSTAT_REFUSED; + + free(pi->recv->fname); + pi->recv->fname = NULL; + + return pi->recv->status == FSTAT_SKIPPED ? 2 : 1; + } + else if( pi->recv->mod_time == localtogmt(st.st_mtime) + && pi->recv->bytes_total >= st.st_size ) + { + pi->recv->bytes_skipped = st.st_size; + pi->recv->bytes_received = pi->recv->bytes_skipped; + + log("recv: receiving \"%s\" from offset %ld", + pi->recv->fname, (long)pi->recv->bytes_skipped); + + openmode = "a"; + } + } + } + + /* + * Check, there is enough space in our inbound + */ + if (openmode == "a") needed_bytes_total = minfree + pi->recv->bytes_total - pi->recv->bytes_skipped; + else needed_bytes_total = minfree + pi->recv->bytes_total; + + if( minfree > 0 && getfreespace(state.inbound) < needed_bytes_total ) + { + log("recv: not enough free space in inbound -> refuse"); + pi->recv->status = FSTAT_REFUSED; + return(1); + } + + DEB((D_PROT, "p_rx_fopen: call fopen(\"%s\", \"%s\")", + pi->recv->fname, openmode)); + + if( (pi->recv->fp = file_open(pi->recv->fname, openmode)) == NULL ) + { + logerr("recv: cannot open \"%s\" -> refuse", pi->recv->fname); + + pi->recv->status = FSTAT_REFUSED; + free(pi->recv->fname); + pi->recv->fname = NULL; + + return 1; + } + + if( pi->buffer && pi->buflen > 0 ) + { +#ifdef SETVBUF_REVERSED + setvbuf(pi->recv->fp, _IOFBF, pi->buffer, pi->buflen); +#else + setvbuf(pi->recv->fp, pi->buffer, _IOFBF, pi->buflen); +#endif + } + + return 0; +} + +/***************************************************************************** + * Close receiving file. If it was completly received - move it to the main + * inbound directory. + * + * Arguments: + * pi pointer to the protocol information structure + * + * Return value: + * 0 - successfull call + * 1 - error occured, refuse this file (receive later) + */ +int p_rx_fclose(s_protinfo *pi) +{ + long trans_time = 0; + long cps = 0; + int rc = 0; + struct stat st; + + DEB((D_PROT, "p_rx_fclose: close file \"%s\"", pi->recv->fname)); + + if( pi->recv->fp ) + { + rc = file_close(pi->recv->fp); pi->recv->fp = NULL; + + if( rc ) + { + /* + * This may be any sort of errors, including + * random data corruptions. Return error. + */ + logerr("recv: cannot close file \"%s\"", pi->recv->fname); + return 1; + } + } + + if( pi->recv->status == FSTAT_SKIPPED ) + { + /* + * Remove skipped file from temp. inbound + */ + if( unlink(pi->recv->fname) == -1 && errno != ENOENT ) + logerr("recv: cannot remove skipped file \"%s\"", pi->recv->fname); + } + else + { + /* + * Set original file modification time + */ + if( pi->recv->mod_time ) + { + struct utimbuf tvp; + + tvp.actime = time(NULL); + tvp.modtime = gmttolocal(pi->recv->mod_time); + utime(pi->recv->fname, &tvp); + } + + /* + * Set default file permission to 0600 + */ + if( chmod(pi->recv->fname, (S_IRUSR | S_IWUSR)) == -1 ) + logerr("recv: cannot change mode for file \"%s\"", pi->recv->fname); + } + + /* + * Update incoming traffic structure + */ + prot_traffic_update(&pi->traffic_rcvd, + pi->recv->bytes_received - pi->recv->bytes_skipped, + trans_time, pi->recv->type); + + /* + * If file was received successfuly + */ + if( pi->recv->status == FSTAT_SUCCESS ) + { + /* + * Sanity check. Compare real file length with the + * expected length (reported by the remote side) + */ + if( stat(pi->recv->fname, &st) == -1 ) + { + log("cannot stat received file \"%s\"", pi->recv->fname); + pi->recv->status = FSTAT_REFUSED; + } + else if( st.st_size != pi->recv->bytes_total ) + { + log("received file has invalid size %ld (%ld expected)", + (long)st.st_size, (long)pi->recv->bytes_total); + pi->recv->status = FSTAT_REFUSED; + } + else if( state.reqstat == REQS_ALLOW + && (pi->recv->type & TYPE_REQUEST) ) + { + /* Run our freq processor */ + req_proc(pi->recv->fname, &pi->filelist); + unlink(pi->recv->fname); + } + else if( p_move2inbound(pi) ) + { + log("recv: can't move file into main inbound -> refuse"); + pi->recv->status = FSTAT_REFUSED; + } + } + + /* + * Calculate receive time, CPS, etc + */ + trans_time = (long)time(NULL) - (long)pi->recv->start_time; + + if( trans_time > 0 ) + cps = (long)((pi->recv->bytes_received - pi->recv->bytes_skipped) / trans_time); + + log("rcvd: \"%s\" %ld [%s]: %ld seconds, %ld CPS", + pi->recv->local_name, + (long)(pi->recv->bytes_received - pi->recv->bytes_skipped), + (pi->recv->status == FSTAT_SKIPPED) ? "skipped" : + (pi->recv->status == FSTAT_REFUSED) ? "refused" : + (pi->recv->status == FSTAT_SUCCESS) ? "ok" : "error", + (long)(trans_time > 0) ? trans_time : 0, + (long)(cps > 0) ? cps : 0); + + return pi->recv->status == FSTAT_SUCCESS ? 0 : 1; +} + +/***************************************************************************** + * Check current receiving/sending speeds (CPS), check time limits. + * + * Arguments: + * pi pointer to the protocol information structure + * bidir if hydra, check only one CPS value + * + * Return value: + * PRC_NOERROR - all ok + * PRC_STOPTIME - abort session due to time limits + * PRC_CPSTOOLOW - abort session due low speed + */ +int p_info(s_protinfo *pi, int bidir) +{ + int rc = 0, rx_cps_low = 0, tx_cps_low = 0; + time_t tx_now, rx_now, now; + + now = time(NULL); + + if( pi->send && pi->send->status == FSTAT_PROCESS ) + { + tx_now = (long)time(NULL) - (long)pi->send->start_time; + pi->tx_cps = (pi->send->bytes_sent - pi->send->bytes_skipped) / (tx_now ? tx_now : 1); + + /* Is it FREQ answer? */ + if( pi->freq_timelimit > 0 && (pi->send->type & TYPE_REQANSW) ) + { + /* + * Check FREQ time limit not reached? + */ + if( pi->send_freqtime + tx_now > pi->freq_timelimit ) + { + log("reached FREQ time limit %d second(s)", pi->freq_timelimit); + rc = PRC_STOPTIME; + } + } + + /* Check is transmiting CPS to low */ + if( pi->min_tx_cps ) + { + if( pi->tx_low_cps_time ) + { + if( pi->tx_cps < pi->min_tx_cps ) + { + if( now - pi->tx_low_cps_time >= pi->min_cps_time ) + { + tx_cps_low = 1; + } + } + else + { + pi->tx_low_cps_time = 0; + } + } + else if( pi->tx_cps < pi->min_tx_cps ) + { + pi->tx_low_cps_time = now; + } + } + } /* end of if( txi ) */ + + if( pi->recv && pi->recv->status == FSTAT_PROCESS ) + { + rx_now = (long)time(NULL) - (long)pi->recv->start_time; + pi->rx_cps = (pi->recv->bytes_received - pi->recv->bytes_skipped) / (rx_now ? rx_now : 1); + + /* Check is receiving CPS to low */ + if( pi->min_rx_cps ) + { + if( pi->rx_low_cps_time ) + { + if( pi->rx_cps < pi->min_rx_cps ) + { + if( now - pi->rx_low_cps_time >= pi->min_cps_time ) + { + rx_cps_low = 1; + } + } + else + { + pi->rx_low_cps_time = 0; + } + } + else if( pi->rx_cps < pi->min_rx_cps ) + { + pi->rx_low_cps_time = now; + } + } + } /* end of if( rxi ) */ + + /* check maybe now is a good time to stop it ? =) */ + if( pi->stop_time && now >= pi->stop_time ) + { + log("reached stop time"); + rc = PRC_STOPTIME; + } + + if ( tx_cps_low ) + { + if ( !bidir || rx_cps_low ) { + log("transmitting speed below %d cps", pi->min_tx_cps); + rc = PRC_CPSTOOLOW; + } + } + + if ( rx_cps_low ) + { + if ( !bidir || tx_cps_low ) { + log("receiving speed below %d cps", pi->min_rx_cps); + rc = PRC_CPSTOOLOW; + } + } + + return(rc); +} + +/***************************************************************************** + * Log short session statistic. Output overall Send/Received bytes, avreage + * CPS, on-line time + * + * Arguments: + * pi pointer to the protocol information structure + * + * Return value: + * None + */ +void p_log_txrxstat(const s_protinfo *pi) +{ + char abuf[BF_MAXADDRSTR+1]; + s_faddr tmpaddr = state.node.addr; + int total_time = time_elapsed(pi->start_time); + int files_sent = prot_traffic_total_num(&pi->traffic_sent); + int files_rcvd = prot_traffic_total_num(&pi->traffic_rcvd); + size_t bytes_sent = prot_traffic_total_size(&pi->traffic_sent); + size_t bytes_rcvd = prot_traffic_total_size(&pi->traffic_rcvd); + size_t total_traff = bytes_sent + bytes_rcvd; + size_t total_cps = (total_traff / (total_time ? total_time : 1)); + + tmpaddr.domain[0] = '\0'; /* remove domain from address */ + + log("%s, S/R %ld/%ld, %ld/%ld bytes in %ld seconds, %ld CPS", + ftn_addrstr(abuf, tmpaddr), + files_sent, files_rcvd, + (long)bytes_sent, (long)bytes_rcvd, + (long)((total_time > 0) ? total_time : 0), + (long)((total_cps > 0) ? total_cps : 0)); +} + +/***************************************************************************** + * Do session cleanup. Remove temporary files, remove useless file requests + * + * Arguments: + * pi pointer to the protocol information structure + * + * Return value: + * None + */ +void p_session_cleanup(s_protinfo *pi, bool success) +{ + int i; + s_filelist *ptrl; + + if( success ) + { + /* + * Remove sent file requests after successfull sessions + */ + for( i = 0; i < pi->n_sentfiles; i++ ) + if( (pi->sentfiles[i].type & TYPE_REQUEST) + && (pi->sentfiles[i].status == FSTAT_SUCCESS) ) + { + if( unlink(pi->sentfiles[i].fname) == -1 && errno != ENOENT ) + { + logerr("can't unlink '.req' file \"%s\"", + pi->sentfiles[i].fname); + } + } + } + + /* + * Delete files with action ACTION_FORCEUNLINK + */ + for( ptrl = pi->filelist; ptrl; ptrl = ptrl->next ) + { + /* It must be allready deleted if it is sent */ + if( ptrl->action == ACTION_FORCEUNLINK && ptrl->status != STATUS_SENT ) + { + if( unlink(ptrl->fname) && errno != ENOENT ) + logerr("cannot unlink temporary file \"%s\"", ptrl->fname); + } + } +} + +/***************************************************************************** + * Do all necessary convertions and checks with file names before sending it + * + * Arguments: + * origname pointer to the original file name + * type file type (netmail, arcmail, etc.) + * + * Return value: + * Pointer to the new file name (must be freed) + */ +char *p_convfilename(const char *origname, int type) +{ + const char *p; + char *dest = NULL; + long crc = 0L; + s_faddr addr; + + if( (type & TYPE_NETMAIL) ) + { + /* + * Generate random file name for netmail packets + */ + dest = (char*)xmalloc(32); + sprintf(dest, "%08lx.pkt", (long)rand()); + } + else if( (type & TYPE_ASONAME) == TYPE_ASONAME + && (type & TYPE_ARCMAIL) == TYPE_ARCMAIL ) + { + /* + * Generate new file name for arcmail from AmigaDos style + * outbound, such files looks like "2.5020.1682.9.fr1". + */ + if( (p = strrchr(origname, '.')) ) + crc = getcrc32ccitt(origname, p - origname - 1); + else + crc = getcrc32ccitt(origname, strlen(origname)); + + dest = (char*)xmalloc(32); + sprintf(dest, "%08lx%s", (long)crc, p?p:".fr0"); + } + else if( (type & TYPE_ASONAME) == TYPE_ASONAME + && (type & TYPE_REQUEST) == TYPE_REQUEST ) + { + /* + * Generate new file name for file request from AmigaDos + * style outbound, such files looks like "2.5020.1682.0.req". + */ + dest = (char*)xmalloc(32); + if( out_parse_name_aso(&addr, origname) == 0 ) + sprintf(dest, "%04x%04x.req", addr.net, addr.node); + else + sprintf(dest, "%08lx.req", (long)rand()); + } + else + { + /* + * All other files send with their real name, but: + * 1) remove "nonprintable" characters + * 2) convert files to 8+3 format if remote has no long + * file names support (indicated by $state.sopts.fnc) + */ + if( state.sopts.fnc ) + { + dest = (char*)xmalloc(13); + file_get_dos_name(dest, origname); + } + else + { + dest = (char*)xstrcpy(origname); + if( string_isupper(dest) ) + string_tolower(dest); + } + } + + return dest; +} + +/***************************************************************************** + * Get temporary file name with full path. + * + * Arguments: + * inbound path to temporary inbound directory + * filename file name + * addr remote address \ + * sz file size > Used to generate unique file names + * tm file time / + * + * Return value: + * Pointer to the temporary file name (must be freed) + */ +char *p_gettmpname(const char *inbound, char *filename, s_faddr addr, + size_t sz, time_t tm) +{ + char *dest; + char abuf[BF_MAXADDRSTR+1]; + char bbuf[BF_MAXADDRSTR+30]; + char cbuf[16]; + + sprintf(bbuf, "%s %lx %lx", ftn_addrstr(abuf, addr), (long)sz, (long)tm); + sprintf(cbuf, "%lx", (long)getcrc32ccitt(bbuf, strlen(bbuf))); + + dest = xstrcpy(inbound); + dest = xstrcat(dest, filename); + dest = xstrcat(dest, "."); + dest = xstrcat(dest, cbuf); + + return dest; +} + +#define MAX_TRIES 1024 + +/***************************************************************************** + * Get new file name for received file. Use it when we allready have + * file with such name in inbound directory. + * + * Rename file with the next algorithm: + * + * - For file request. Overwrite existing file + * + * - For netmail or ticfile. Generate new unique + * file name. (1234abcde.pkt -> ab04d51f.pkt) + * + * - For arcmail. Rotate extension chars to make + * unique name. (057d63a6.su0 -> 057d63a6.su1) + * + * - For other files. Try to add a numeric value + * as additional extension ("net5020.ndl.1") + * + * Arguments: + * dirname pointer to the directory (inbound) + * fname pointer to the file name + * type file type (netmail, arcmail, etc.) + * + * Return value: + * Pointer to the new file name with path (must be freed), and + * NULL to indicate error + */ +char *prot_unique_name(char *dirname, char *fname, int type) +{ + int try = 0; + int offs = 0; + char *result = NULL; + char *p; + + if( (type & TYPE_REQUEST) ) + { + result = (char *)xstrcpy(dirname); + result = (char *)xstrcat(result, fname); + } + else if( (type & TYPE_NETMAIL) || (type & TYPE_TICFILE) ) + { + char *ext = (type & TYPE_NETMAIL) ? "pkt" : "tic"; + + offs = strlen(dirname); + result = (char *)xmalloc(offs + 36); + strncpy(result, dirname, offs + 35); + result[offs + 35] = '\0'; + + do + { + ++try; + sprintf(result+offs, "%08lx.%s", (long)rand(), ext); + } + while( !access(result, F_OK) && try < MAX_TRIES ); + } + else if( (type & TYPE_ARCMAIL) ) + { + result = (char *)xstrcpy(dirname); + result = (char *)xstrcat(result, fname); + + p = result + strlen(result) - 1; + + do + { + ++try; + + if( (*p >= '0') && (*p <= '8') ) + ++*p; + else if( (*p >= 'A') && (*p <= 'Y') ) + ++*p; + else if( (*p >= 'a') && (*p <= 'y') ) + ++*p; + else if( (*p == '9') ) + *p = 'a'; + else if( (*p == 'z') ) + *p = 'A'; + else if( --p < result || *p == '.' || *p == '/' ) + { + free(result); + result = NULL; + break; + } + } + while( !access(result, F_OK) && try < MAX_TRIES ); + } + else + { + result = (char *)xstrcpy(dirname); + result = (char *)xstrcat(result, fname); + + offs = strlen(result); + + result = (char *)xrealloc(result, offs + 16); + + if( result[offs-1] != '.' ) + { + result[offs++] = '.'; + result[offs ] = '\0'; + } + + do + { + ++try; + sprintf(result+offs, "%d", try); + } + while( !access(result, F_OK) && try < MAX_TRIES ); + } + + if( try >= MAX_TRIES ) + { + if( result ) + free(result); + + return NULL; + } + + return result; +} + +/***************************************************************************** + * Release memory used by file information structure + * + * Arguments: + * fi pointer to the file information structure + * + * Return value: + * None + */ +void deinit_finfo(s_finfo *fi) +{ + if( fi->fp ) + fclose(fi->fp); + + if( fi->local_name ) + free(fi->local_name); + if( fi->net_name ) + free(fi->net_name); + if( fi->fname ) + free(fi->fname); + + memset(fi, '\0', sizeof(s_finfo)); +} + +/***************************************************************************** + * Init protocol information structure. Set all necessary options, such as + * minimal CPSes, start/stop time, etc. + * + * Arguments: + * pi pointer to the protocol information structure + * caller are we caller? + * + * Return value: + * None + */ +void init_protinfo(s_protinfo *pi, bool caller) +{ + long tmp; + long sesslimit; + + memset(pi, '\0', sizeof(s_protinfo)); + + pi->start_time = time(NULL); + + if( (pi->buflen = conf_number(cf_recv_buffer_size)) > 0 ) + pi->buflen = (pi->buflen / 2048) * 2048; + else + pi->buflen = 32768; + + if( pi->buflen > 0 ) + pi->buffer = (char*)xmalloc(pi->buflen); + + if( (tmp = conf_number(cf_min_cps_time)) > 0 ) + pi->min_cps_time = tmp; + else + pi->min_cps_time = 60; + + /* + * Set abort time if session limit was specified + */ + if( caller ) + sesslimit = conf_number(cf_session_limit_out); + else + sesslimit = conf_number(cf_session_limit_in); + + if( sesslimit > 0 ) + pi->stop_time = time(0) + sesslimit; + + /* + * Set minimal transmit speed (CPS) + */ + if( (tmp = conf_number(cf_min_cps_send)) > 0 ) + pi->min_tx_cps = tmp; + else + { + if( state.handshake->protocol == PROT_ZMODEM + || state.handshake->protocol == PROT_ZEDZAP + || state.handshake->protocol == PROT_DIRZAP ) + tmp = conf_connlist(cf_zmodem_mincps_send, state.connspeed); + else if( state.handshake->protocol == PROT_HYDRA ) + tmp = conf_connlist(cf_hydra_mincps_send, state.connspeed); + else + tmp = 0; + + if( tmp > 0 ) + pi->min_tx_cps = tmp; + } + + /* + * Set minimal receive speed (CPS) + */ + if( (tmp = conf_number(cf_min_cps_recv)) > 0 ) + pi->min_rx_cps = tmp; + else + { + if( state.handshake->protocol == PROT_ZMODEM + || state.handshake->protocol == PROT_ZEDZAP + || state.handshake->protocol == PROT_DIRZAP ) + tmp = conf_connlist(cf_zmodem_mincps_recv, state.connspeed); + else if( state.handshake->protocol == PROT_HYDRA ) + tmp = conf_connlist(cf_hydra_mincps_recv, state.connspeed); + else + tmp = 0; + + if( tmp > 0 ) + pi->min_rx_cps = tmp; + } + + /* + * Report about selected limits + */ + if( sesslimit > 0 && (pi->min_tx_cps > 0 || pi->min_rx_cps > 0) ) + log("use restrictions: %d/%d cps, %d seconds", pi->min_tx_cps, pi->min_rx_cps, sesslimit); + else if( pi->min_tx_cps > 0 || pi->min_rx_cps > 0 ) + log("use restrictions: %d/%d cps", pi->min_tx_cps, pi->min_rx_cps); + else if( sesslimit > 0 ) + log("use restrictions: %d seconds", sesslimit); + + DEB((D_PROT, "protinfo_init: min_tx_cps = %ld, min_rx_cps = %ld", + (long)pi->min_tx_cps, (long)pi->min_rx_cps)); + DEB((D_PROT, "protinfo_init: buffersize = %ld, stoptime = %ld", + (long)pi->min_tx_cps, (long)pi->min_rx_cps)); +} + +/***************************************************************************** + * Release memory used by protocol information structure + * + * Arguments: + * pi pointer to the protocol information structure + * + * Return value: + * None + */ +void deinit_protinfo(s_protinfo *pi) +{ + int i; + + for( i = 0; i < pi->n_sentfiles; i++ ) + deinit_finfo(&pi->sentfiles[i]); + + for( i = 0; i < pi->n_rcvdfiles; i++ ) + deinit_finfo(&pi->rcvdfiles[i]); + + if( pi->buffer ) + free(pi->buffer); + if( pi->sentfiles ) + free(pi->sentfiles); + if( pi->rcvdfiles ) + free(pi->rcvdfiles); + + memset(pi, '\0', sizeof(s_protinfo)); +} diff --git a/source/bforce/prot_emsi.c b/source/bforce/prot_emsi.c new file mode 100644 index 0000000..37326e6 --- /dev/null +++ b/source/bforce/prot_emsi.c @@ -0,0 +1,842 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + * + * BUG: When we resend EMSIDAT packet, it's TRX# field is most probable + * out of date. + */ + +#include "includes.h" +#include "confread.h" +#include "version.h" +#include "logger.h" +#include "util.h" +#include "io.h" +#include "nodelist.h" +#include "session.h" +#include "prot_common.h" +#include "prot_emsi.h" + +/* + * #define EMSI_INQ "**EMSI_INQC816" + * #define EMSI_REQ "**EMSI_REQA77E" + * #define EMSI_ACK "**EMSI_ACKA490" + * #define EMSI_NAK "**EMSI_NAKEEC3" + * #define EMSI_CLI "**EMSI_CLIFA8C" + * #define EMSI_ICI "**EMSI_ICI2D73" + * #define EMSI_HBT "**EMSI_HBTEAEE" + * #define EMSI_IRQ "**EMSI_IRQ8E08" + */ + +typedef struct tx_emsidat { + int caller; + int tries; + time_t mast_timer; + time_t sync_timer; + char buf[13]; + int emsi_seq; + int nakcount; /* count received EMSI_NAK */ + s_emsi *local_emsi; +} s_tx_emsidat; + +typedef struct rx_emsidat { + int caller; + int rx_ack; /* strip second EMSI_ACK */ + int tries; + int tries_recv; + time_t mast_timer; + time_t sync_timer; + char buf[13]; + int emsi_seq; + s_emsi *remote_emsi; +} s_rx_emsidat; + +/* + * State machine (TODO: REMOVE!) Now it is used only by EMSI protocol. + */ +static int state_machine(s_states *sm, void *data) +{ + signed int cur_state = 0; + + do + { + DEB((D_STATEM, "state_machine: entering with state \"%s\" (%d)", + sm[cur_state].st_name, cur_state)); + cur_state = (*(sm[cur_state].proc))(data); + DEB((D_STATEM, "state_machine: return \"%s\" (%d)", + (cur_state>0)?sm[cur_state].st_name:"finish", cur_state)); + } + while( cur_state > 0 ); + + return(cur_state); +} + +/* ------------------------------------------------------------------------- */ +/* Transmite EMSI_DAT packet state machine routines */ +/* ------------------------------------------------------------------------- */ + +/* SM0 */ +static int sm_tx_init(s_tx_emsidat *d) +{ + timer_set(&d->mast_timer, 60); + + return(SM1); +} + +/* SM1 */ +static int sm_tx_senddat(s_tx_emsidat *d) +{ + char *emsi_dat = NULL; + char buf[8]; + + if( ++d->tries > 6 ) + { + log("too many tries sending emsi data"); + return(SME); + } + + if( d->tries > 1 ) + log("emsi data send - retry %d", d->tries - 1); + + DEB((D_HSHAKE, "sm_tx_senddat: try number %d", d->tries)); + + if( (emsi_dat = emsi_createdat(d->local_emsi)) == NULL ) + { + log("cannot create emsi data packet"); + return(SME); + } + + DEB((D_HSHAKE, "sm_tx_senddat: emsi: \"%s\"", emsi_dat)); + + if( tty_puts(emsi_dat, 60) < 0 ) + { + free(emsi_dat); + return SME; + } + + /* + * Calculate and send CRC-16 of our emsi packet + */ + sprintf(buf, "%04hX\r", + (short unsigned)getcrc16xmodem(emsi_dat+2, strlen(emsi_dat+2))); + + free(emsi_dat); emsi_dat = NULL; + + if( PUTSTR(buf) < 0 || FLUSHOUT() < 0 ) + return SME; + + return SM2; +} + +/* SM2 */ +static int sm_tx_waitseq(s_tx_emsidat *d) +{ + int rc, pos = 0; + + timer_set(&d->sync_timer, (d->tries > 1) ? 20 : 10); + + while(1) + { + if( timer_expired(d->mast_timer) ) + { + DEB((D_HSHAKE, "sm_tx_waitseq: master timer expired")); + log("master timer expired"); + return(SME); + } + + if( timer_expired(d->sync_timer) ) + { + DEB((D_HSHAKE, "sm_tx_waitseq: sync timer expired")); + return(SM1); + } + + if( (rc = GETCHAR(1)) < 0 ) + { + if( rc != TTY_TIMEOUT ) + { + DEB((D_HSHAKE, "sm_rx_waitseq: got ERROR/HANGUP")); + return SME; + } + } + else if( rc == XON || rc == XOFF ) + { + /* Do nothing. Drop them down */ + } + else if( rc == '*' ) + { + memset(d->buf, '\0', sizeof(d->buf)); + pos = 0; + d->emsi_seq = 1; + } + else if( d->emsi_seq && rc > ' ' && rc < '~' ) + { + if( pos < sizeof(d->buf)-1 ) + { + d->buf[pos++] = rc; + d->buf[pos ] = '\0'; + } + + if( pos == (sizeof(d->buf) - 1) ) + { + DEB((D_HSHAKE, "sm_tx_waitseq: emsi buffer full \"%s\"", d->buf)); + + d->emsi_seq = 0; + + if( !strncasecmp(d->buf, "EMSI_REQA77E", 12) ) + { + /* Do nothing. Drop it down */ + } + else if( !strncasecmp(d->buf, "EMSI_ACKA490", 12) ) + { + /* + * Remote acknowleged our + * emsi data packet. exit. + */ + return SM0; + } + else if( !strncasecmp(d->buf, "EMSI_NAKEEC3", 12) ) + { + /* + * Remote failed on our emsi data + * packet. Resend EMSI_DAT only after + * first EMSI_NAK + */ + DEB((D_HSHAKE, "sm_tx_waitseq: got NAK")); + if( !d->nakcount++ ) + return SM1; + } + else if( !strncasecmp(d->buf, "EMSI_INQC816", 12) ) + { + /* + * Do nothing. Just update sync timer + */ + return SM2; + } + else if( !strncasecmp(d->buf, "EMSI_DAT", 8) ) + { + /* + * 1) We are calling system + * We got an echo of our sequence, + * possible they don't know about + * FIDO. yet :) Resend EMSI_INQ + * again. + * 2) We are asnwering system + * Think where is a stupid mailer + * that didn't seen our EMSI_ACK, + * so send it again in hope to the + * best + */ + DEB((D_HSHAKE, "sm_tx_waitseq: got echo \"%s\"", + string_printable(d->buf))); + + if( d->caller ) + { + /* Wait for a login prompt */ + sleep(2); + + if( PUTSTR("**EMSI_INQC816\r") < 0 + || FLUSHOUT() < 0 ) + return SME; + + /* Wait for a password prompt */ + sleep(2); + + if( PUTSTR("**EMSI_INQC816\r") < 0 + || FLUSHOUT() < 0 ) + return SME; + + return SM1; + } + else + { + /* Send acknowlegment */ + if( PUTSTR("**EMSI_ACKA490\r**EMSI_ACKA490\r") < 0 ) + return SME; + if( FLUSHOUT() < 0 ) + return SME; + } + } + else + { + DEB((D_HSHAKE, "got unexpected emsi sequence: \"%s\"", + string_printable(d->buf))); + log("got unexpected emsi sequence \"%s\"", + string_printable(d->buf)); + } + } + } + else if( d->emsi_seq ) + { + d->emsi_seq = 0; + DEB((D_HSHAKE, "sm_tx_waitseq: bad character 0x%02x in \"%s\"", + rc, string_printable(d->buf))); + } + } + + return SME; +} + +static s_states st_tx_emsidat[] = +{ + { "sm_tx_init", sm_tx_init }, + { "sm_tx_senddat", sm_tx_senddat }, + { "sm_tx_waitseq", sm_tx_waitseq } +}; + +int emsi_send_emsidat(s_emsi *local_emsi) +{ + s_tx_emsidat d; + + memset(&d, '\0', sizeof(s_tx_emsidat)); + + d.caller = state.caller; + d.local_emsi = local_emsi; + + return state_machine(st_tx_emsidat, &d) ? 1 : 0; +} + +/* ------------------------------------------------------------------------- */ +/* Receive EMSI_DAT packet state machine routines */ +/* ------------------------------------------------------------------------- */ + +/* SM0 */ +static int sm_rx_init(s_rx_emsidat *d) +{ + timer_set(&d->mast_timer, 60); + timer_set(&d->sync_timer, 20); + + return SM1; +} + +/* SM1 */ +static int sm_rx_sendnak(s_rx_emsidat *d) +{ + if( ++d->tries > 6 ) + { + log("too many tries resyncing with remote"); + return(SME); + } + + DEB((D_HSHAKE, "sm_rx_sendnak: try number %d", d->tries)); + + if( !d->caller ) + { + if( conf_boolean(cf_emsi_slave_sends_nak) + && PUTSTR("**EMSI_NAKEEC3\r") < 0 ) + return SME; + if( PUTSTR("**EMSI_REQA77E\r") < 0 ) + return SME; + } + else if( d->tries > 1 ) + { + if( PUTSTR("**EMSI_NAKEEC3\r") < 0 ) + return SME; + } + + if( FLUSHOUT() < 0 ) + return SME; + + return SM2; +} + +/* SM2 */ +static int sm_rx_waitseq(s_rx_emsidat *d) +{ + int rc, pos = 0; + + timer_set(&d->sync_timer, 20); + + while(1) + { + if( timer_expired(d->mast_timer) ) + { + DEB((D_HSHAKE, "sm_rx_waitseq: master timer expired")); + log("master timer expired"); + return SME; + } + + if( timer_expired(d->sync_timer) ) + { + DEB((D_HSHAKE, "sm_rx_waitseq: sync timer expired")); + return SM1; + } + + if( (rc = GETCHAR(1)) < 0 ) + { + if( rc != TTY_TIMEOUT ) + { + DEB((D_HSHAKE, "sm_rx_waitseq: got ERROR/HANGUP")); + return SME; + } + } + else if( rc == XON || rc == XOFF ) + { + /* Do nothing. Drop them down */ + } + else if( rc == '*' ) + { + memset(d->buf, '\0', sizeof(d->buf)); + pos = 0; + d->emsi_seq = 1; + } + else if( d->emsi_seq && rc > ' ' && rc < '~' ) + { + if( pos < sizeof(d->buf)-1 ) + { + d->buf[pos++] = rc; + d->buf[pos ] = '\0'; + } + + if( pos == sizeof(d->buf)-1 ) + { + DEB((D_HSHAKE, "sm_rx_waitseq: emsi buffer full \"%s\"", d->buf)); + + d->emsi_seq = 0; + + if( d->caller && !strncasecmp(d->buf, "EMSI_ACKA490", 12) ) + { + /* Do nothing. Drop it down. */ + } + else if( !strncasecmp(d->buf, "EMSI_HBTEAEE", 12) ) + { + /* + * Remote wants some time to think + */ + return SM2; + } + else if( !strncasecmp(d->buf, "EMSI_DAT", 8) ) + { + /* + * Start receiving emsi data packet + */ + return SM3; + } + else + { + DEB((D_HSHAKE, "got unexpected emsi sequence: \"%s\"", + string_printable(d->buf))); + log("got unexpected emsi sequence \"%s\"", + string_printable(d->buf)); + } + } + } + else if( d->emsi_seq ) + { + d->emsi_seq = 0; + DEB((D_HSHAKE, "sm_rx_waitseq: bad character 0x%02x in \"%s\"", + rc, string_printable(d->buf))); + } + } + + return SME; +} + +/* SM3 */ +static int sm_rx_getdat(s_rx_emsidat *d) +{ + int rc = 0; + int pos = 0; + int emsi_len = 0; + short unsigned ourcrc; + short unsigned remcrc; + char *emsi_dat = NULL; + + if( d->tries_recv++ ) + log("emsi data receive - retry %d", d->tries_recv); + + /* + * At this point, there is a EMSI_DATXXXX packet in + * the buffer, there XXXX is the hex length of emsi + * data packet + */ + if( strspn(d->buf+8, "0123456789abcdefABCDEF") != 4 ) + return SM1; + + if( sscanf(d->buf+8, "%04x", &emsi_len) != 1 ) + return SM1; + + /* + * Don't receive emsi packet's longer our "limit" + */ + if( emsi_len > EMSI_MAXDAT ) + { + CLEARIN(); + log("emsi data packet too long %db (maximum %db allowed)", + emsi_len, EMSI_MAXDAT); + return SM1; + } + + /* Increase packet's length on CRC length */ + emsi_len += 16; + + emsi_dat = (char*)xmalloc(emsi_len + 1); + strncpy(emsi_dat, d->buf, 12); + pos = 12; + + while( pos < emsi_len ) + { + if( timer_expired(d->mast_timer) ) + break; + + if( (rc = GETCHAR(1)) < 0 ) + { + if( rc != TTY_TIMEOUT ) + break; + } + else + { + emsi_dat[pos++] = (unsigned char)rc; + emsi_dat[pos ] = '\0'; + } + } + + if( pos != emsi_len ) + { + /* Fatal error occured */ + DEB((D_HSHAKE, "sm_rx_getdat: can't get emsi_dat packet")); + DEB((D_HSHAKE, "sm_rx_getdat: buffer: \"%s\"", + string_printable(emsi_dat))); + free(emsi_dat); + return SME; + } + + DEB((D_HSHAKE, "sm_rx_getdat: got \"%s\"", + string_printable(emsi_dat))); + + /* + * Get CRC given by remote + */ + if( sscanf(emsi_dat + emsi_len - 4 , "%04hX", &remcrc) != 1 ) + { + log("bad emsi data packet (can't get CRC16)"); + free(emsi_dat); + + return(SM1); + } + + /* + * Calculate our own crc of the data packet + */ + ourcrc = getcrc16xmodem(emsi_dat, emsi_len-4); + + /* + * Compare our and remote CRCs + */ + if( ourcrc != remcrc ) + { + DEB((D_HSHAKE, "sm_rx_getdat: our = %hX, remote = %hX", ourcrc, remcrc)); + log("got emsi data packet with bad CRC"); + free(emsi_dat); + + return SM1; + } + + /* + * Parse received emsi data packet. All obtained + * information will be stored in d->remote_emsi + */ + rc = emsi_parsedat(emsi_dat+12, d->remote_emsi); + + free(emsi_dat); + + if( rc ) + { + log("received invalid emsi data packet"); + return SM1; + } + + /* Send acknowlegment */ + if( PUTSTR("**EMSI_ACKA490\r**EMSI_ACKA490\r") < 0 ) + return SME; + if( FLUSHOUT() < 0 ) + return SME; + + return SM0; +} + +static s_states st_rx_emsidat[] = +{ + { "sm_rx_init", sm_rx_init }, + { "sm_rx_sendnak", sm_rx_sendnak }, + { "sm_rx_waitseq", sm_rx_waitseq }, + { "sm_rx_getdat", sm_rx_getdat } +}; + +int emsi_recv_emsidat(s_emsi *remote_emsi) +{ + s_rx_emsidat d; + + memset(&d, '\0', sizeof(s_rx_emsidat)); + + d.caller = state.caller; + d.remote_emsi = remote_emsi; + + return state_machine(st_rx_emsidat, &d) ? 1 : 0; +} + +/* ------------------------------------------------------------------------- */ +/* Fill/update our outgoing emsi oriented structure */ +/* ------------------------------------------------------------------------- */ +void emsi_set_sysinfo(s_emsi *emsi, s_emsi *remote_emsi, int hrc, + e_protocol protocol) +{ + char buf[64]; + s_cval_entry *addr_ptr; + s_cval_entry *hide_ptr; + s_faddr *primary = NULL; + + const long options = conf_options(cf_options); + const long speed = conf_number(cf_max_speed); + const char *p_systname = conf_string(cf_system_name); + const char *p_location = conf_string(cf_location); + const char *p_sysopname = conf_string(cf_sysop_name); + const char *p_phone = conf_string(cf_phone); + const char *p_flags = conf_string(cf_flags); + const char *p_emsioh = conf_string(cf_emsi_OH_time); + const char *p_emsifr = conf_string(cf_emsi_FR_time); + + /* free previously allocated memory */ + if( emsi->addrs ) free(emsi->addrs); + + memset(emsi, '\0', sizeof(s_emsi)); + + /* ----------------------------------------------------------------- */ + /* Data for {EMSI} field */ + /* ----------------------------------------------------------------- */ + emsi->have_emsi = 1; + + /* Set best primary address */ + primary = session_get_bestaka(state.node.addr); + + /* Add primary address */ + if( primary ) + session_addrs_add(&emsi->addrs, &emsi->anum, *primary); + + /* Add other AKAs */ + for( addr_ptr = conf_first(cf_address); addr_ptr; + addr_ptr = conf_next(addr_ptr) ) + { + for( hide_ptr = conf_first(cf_hide_our_aka); hide_ptr; + hide_ptr = conf_next(hide_ptr) ) + { + if( !ftn_addrcomp(hide_ptr->d.falist.addr, addr_ptr->d.falist.addr) ) + break; + } + + if( !hide_ptr && primary != &addr_ptr->d.falist.addr ) + session_addrs_add(&emsi->addrs, &emsi->anum, + addr_ptr->d.falist.addr); + } + + if( emsi->anum == 0 ) + log("warning: no addresses will be presented to remote"); + + /* session password */ + if( state.caller ) + { + session_get_password(state.node.addr, emsi->passwd, sizeof(emsi->passwd)); + } + else if( hrc == HRC_OK ) + { + /* Satisfy remote with their password */ + const char *p = state.handshake->remote_password(state.handshake); + if( p ) + strnxcpy(emsi->passwd, p, sizeof(emsi->passwd)); + } + + /* link codes */ + if( state.caller ) /* CALLER */ + { + if( (options & OPTIONS_NO_RH1) != OPTIONS_NO_RH1 + && (options & OPTIONS_NO_HYDRA) != OPTIONS_NO_HYDRA) + { emsi->linkcodes.RH1 = 1; } + + if( (options & OPTIONS_NO_PICKUP) == OPTIONS_NO_PICKUP ) + { emsi->linkcodes.NPU = 1; } + else + { emsi->linkcodes.PUA = 1; } + + if( (options & OPTIONS_MAILONLY) == OPTIONS_MAILONLY ) + { emsi->linkcodes.HXT = 1; } + + if( (options & OPTIONS_NO_EMSI_II) != OPTIONS_NO_EMSI_II ) + { + /* EMSI-II */ + if( (options & OPTIONS_HOLDREQ) != OPTIONS_HOLDREQ ) + { emsi->linkcodes.RMA = 1; } + } + else + { + /* EMSI-I */ + emsi->linkcodes.N81 = 1; + } + } + else if( (remote_emsi->compcodes.EII == 1) + && (options & OPTIONS_NO_EMSI_II) != OPTIONS_NO_EMSI_II ) + { + /* ANSWER/EMSI-II */ + if( remote_emsi->linkcodes.RH1 && protocol == PROT_HYDRA ) + { emsi->linkcodes.RH1 = 1; } + + if( state.reqstat == REQS_ALLOW && remote_emsi->linkcodes.RMA ) + { emsi->linkcodes.RMA = 1; } + else if( state.reqstat == REQS_NOTALLOW ) + { emsi->linkcodes.HRQ = 1; } + + if( (options & OPTIONS_MAILONLY) == OPTIONS_MAILONLY ) + { emsi->linkcodes.HXT = 1; } + } + else + { + /* ANSWER/EMSI-I */ + if( remote_emsi->linkcodes.RH1 && protocol == PROT_HYDRA ) + { emsi->linkcodes.RH1 = 1; } + + if( state.reqstat == REQS_NOTALLOW ) + { emsi->linkcodes.HRQ = 1; } + + if( (options & OPTIONS_MAILONLY) == OPTIONS_MAILONLY ) + { emsi->linkcodes.HXT = 1; } + } + + /* compatibility codes */ + if( state.caller ) + { + if( (options & OPTIONS_NO_EMSI_II) != OPTIONS_NO_EMSI_II ) + { + /* EMSI-II */ + emsi->compcodes.EII = 1; + } + else + { + /* EMSI-I */ + emsi->compcodes.ARC = 1; + emsi->compcodes.XMA = 1; + } + if( (options & OPTIONS_NO_ZMODEM) != OPTIONS_NO_ZMODEM ) + { emsi->compcodes.ZMO = 1; } + if( (options & OPTIONS_NO_ZEDZAP) != OPTIONS_NO_ZEDZAP ) + { emsi->compcodes.ZAP = 1; } + if( (options & OPTIONS_NO_DIRZAP) != OPTIONS_NO_DIRZAP ) + { emsi->compcodes.DZA = 1; } + if( (options & OPTIONS_NO_JANUS) != OPTIONS_NO_JANUS ) + { emsi->compcodes.JAN = 1; } + if( (options & OPTIONS_NO_HYDRA) != OPTIONS_NO_HYDRA ) + { emsi->compcodes.HYD = 1; } + } + else + { + if( (remote_emsi->compcodes.EII == 1) + && (options & OPTIONS_NO_EMSI_II) != OPTIONS_NO_EMSI_II ) + { + /* EMSI-II */ + emsi->compcodes.EII = 1; + } + else + { + /* EMSI-I */ + emsi->compcodes.ARC = 1; + emsi->compcodes.XMA = 1; + } + + if( state.reqstat == REQS_DISABLED ) + { emsi->compcodes.NRQ = 1; } + + switch(protocol) { + case PROT_NOPROT: emsi->compcodes.NCP = 1; break; + case PROT_ZMODEM: emsi->compcodes.ZMO = 1; break; + case PROT_ZEDZAP: emsi->compcodes.ZAP = 1; break; + case PROT_DIRZAP: emsi->compcodes.DZA = 1; break; + case PROT_JANUS: emsi->compcodes.JAN = 1; break; + case PROT_HYDRA: emsi->compcodes.HYD = 1; break; + default: ASSERT(FALSE); break; + } + } + + strnxcpy(emsi->m_pid, BF_EMSI_NUM, sizeof(emsi->m_pid)); + strnxcpy(emsi->m_name, BF_EMSI_NAME, sizeof(emsi->m_name)); + + if( hrc != HRC_BAD_PASSWD ) + { + strnxcpy(emsi->m_ver, BF_EMSI_VER, sizeof(emsi->m_ver)); + strnxcpy(emsi->m_reg, BF_EMSI_REG, sizeof(emsi->m_reg)); + } + else + { + strnxcpy(emsi->m_ver, "?", sizeof(emsi->m_ver)); + strnxcpy(emsi->m_reg, "?", sizeof(emsi->m_reg)); + } + + /* ----------------------------------------------------------------- */ + /* Data for {IDENT} field */ + /* ----------------------------------------------------------------- */ + emsi->have_ident = 1; + emsi->speed = (speed > 0) ? speed : 300; + + strnxcpy(emsi->sysop, p_sysopname ? p_sysopname : "Unknown", sizeof(emsi->sysop)); + strnxcpy(emsi->phone, p_phone ? p_phone : "Unknown", sizeof(emsi->phone)); + + switch(hrc) { + case HRC_BAD_PASSWD: + strnxcpy(emsi->sname, "Bad password", sizeof(emsi->sname)); + strnxcpy(emsi->location, "Check security table", sizeof(emsi->location)); + strnxcpy(emsi->flags, "Password Error", sizeof(emsi->flags)); + break; + case HRC_LOW_SPEED: + strnxcpy(emsi->sname, "Connect speed too low", sizeof(emsi->sname)); + strnxcpy(emsi->location, "Buy new modem and call again", sizeof(emsi->location)); + sprintf(buf, "Minimal speed: %ldbps", (long)state.minspeed); + strnxcpy(emsi->flags, buf, sizeof(emsi->flags)); + break; + case HRC_BUSY: + strnxcpy(emsi->sname, "All AKAs are busy", sizeof(emsi->sname)); + strnxcpy(emsi->location, "Possible another session is running", sizeof(emsi->location)); + strnxcpy(emsi->flags, "Please, call later", sizeof(emsi->flags)); + break; + default: + strnxcpy(emsi->sname, p_systname ? p_systname : "Unknown", sizeof(emsi->sname)); + strnxcpy(emsi->location, p_location ? p_location : "Unknown", sizeof(emsi->location)); + strnxcpy(emsi->flags, p_flags ? p_flags : "MO", sizeof(emsi->flags)); + } + + /* ----------------------------------------------------------------- */ + /* Data for {OHFR} field */ + /* ----------------------------------------------------------------- */ + if( p_emsioh && *p_emsioh && hrc != HRC_BAD_PASSWD ) + { + emsi->have_ohfr = 1; + strnxcpy(emsi->oh_time, p_emsioh, sizeof(emsi->oh_time)); + if( p_emsifr && *p_emsifr ) + strnxcpy(emsi->fr_time, p_emsifr, sizeof(emsi->fr_time)); + } + + /* ----------------------------------------------------------------- */ + /* Data for {TRX#} field */ + /* ----------------------------------------------------------------- */ + emsi->have_trx = 1; + emsi->time = localtogmt(time(NULL)); + + /* ----------------------------------------------------------------- */ + /* Data for {TRAF} and {MOH#} fields */ + /* ----------------------------------------------------------------- */ + if( state.caller == 0 && hrc != HRC_BAD_PASSWD ) + { + emsi->have_traf = 1; + emsi->netmail_size = state.traff_send.netmail_size; + emsi->arcmail_size = state.traff_send.arcmail_size; + if ( state.traff_send.files_size ) + { + emsi->have_moh = 1; + emsi->files_size = state.traff_send.files_size; + } + } +} + diff --git a/source/bforce/prot_emsi_api.c b/source/bforce/prot_emsi_api.c new file mode 100644 index 0000000..f230a68 --- /dev/null +++ b/source/bforce/prot_emsi_api.c @@ -0,0 +1,480 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "version.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" +#include "session.h" +#include "prot_emsi.h" + +void emsi_init(s_handshake_protocol *THIS); +void emsi_deinit(s_handshake_protocol *THIS); +int emsi_incoming(s_handshake_protocol *THIS); +int emsi_outgoing(s_handshake_protocol *THIS); +s_faddr *emsi_remote_address(s_handshake_protocol *THIS); +char *emsi_remote_password(s_handshake_protocol *THIS); +char *emsi_remote_sysop_name(s_handshake_protocol *THIS); +char *emsi_remote_system_name(s_handshake_protocol *THIS); +char *emsi_remote_location(s_handshake_protocol *THIS); +char *emsi_remote_phone(s_handshake_protocol *THIS); +char *emsi_remote_flags(s_handshake_protocol *THIS); +char *emsi_remote_mailer(s_handshake_protocol *THIS); +int emsi_remote_traffic(s_handshake_protocol *THIS, s_traffic *dest); +s_faddr *emsi_local_address(s_handshake_protocol *THIS); +char *emsi_local_password(s_handshake_protocol *THIS); + +s_handshake_protocol handshake_protocol_emsi = { + /* Section 1 */ + "EMSI", + "Joaquim H. Homrighausen", + "FSC-0056,0088", + NULL, + NULL, + 0, + emsi_init, + emsi_deinit, + emsi_incoming, + emsi_outgoing, + /* Section 2 */ + emsi_remote_address, + emsi_remote_password, + emsi_remote_sysop_name, + emsi_remote_system_name, + emsi_remote_location, + emsi_remote_phone, + emsi_remote_flags, + emsi_remote_mailer, + emsi_remote_traffic, + /* Section 3 */ + emsi_local_address, + emsi_local_password +}; + +static void emsi_set_send_options(s_emsi *remote_emsi) +{ + session_set_send_options(); + + if( remote_emsi->linkcodes.FNC ) + state.sopts.fnc = 1; + + if( remote_emsi->linkcodes.RH1 ) + state.sopts.hydraRH1 = 1; + + if( state.caller ) + { + if( remote_emsi->linkcodes.HRQ + || remote_emsi->compcodes.NRQ ) + state.sopts.holdreq = 1; + if( remote_emsi->linkcodes.HAT ) + state.sopts.holdall = 1; + if( remote_emsi->linkcodes.HXT ) + state.sopts.holdxt = 1; + } + else + { + if( remote_emsi->linkcodes.NPU ) + state.sopts.holdall = 1; + if( remote_emsi->linkcodes.PMO ) + state.sopts.holdfiles = 1; + if( remote_emsi->linkcodes.NRQ ) + state.sopts.holdreq = 1; + } +} + +void emsi_init(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data == NULL); + ASSERT(THIS->local_data == NULL); + + THIS->remote_data = (char *)xmalloc(sizeof(s_emsi)); + THIS->local_data = (char *)xmalloc(sizeof(s_emsi)); + + memset(THIS->remote_data, '\0', sizeof(s_emsi)); + memset(THIS->local_data, '\0', sizeof(s_emsi)); +} + +void emsi_deinit(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + ASSERT(THIS->local_data); + + if( THIS->remote_data ) + { + memset(THIS->remote_data, '\0', sizeof(s_emsi)); + free(THIS->remote_data); + } + + if( THIS->local_data ) + { + memset(THIS->local_data, '\0', sizeof(s_emsi)); + free(THIS->local_data); + } +} + +/* + * Do incoming emsi session + */ +int emsi_incoming(s_handshake_protocol *THIS) +{ + int rc = HRC_OK; + s_emsi *remote_emsi = NULL; + s_emsi *local_emsi = NULL; + + ASSERT(THIS); + ASSERT(THIS->remote_data); + ASSERT(THIS->local_data); + + remote_emsi = (s_emsi *)THIS->remote_data; + local_emsi = (s_emsi *)THIS->local_data; + + /* + * Receive EMSI_DAT packet + */ + if( emsi_recv_emsidat(remote_emsi) ) + return HRC_OTHER_ERR; + + /* + * Check password(s) + */ + if( session_addrs_check(remote_emsi->addrs, remote_emsi->anum, + remote_emsi->passwd, NULL, 0) ) + { + rc = HRC_BAD_PASSWD; + /* Don't return. Send EMSI_DAT with + * invalid password messages */ + } + else + { + /* Lock (create BSY) remote addresses */ + if( session_addrs_lock(remote_emsi->addrs, remote_emsi->anum) ) + { + log("all remote addresses are busy"); + rc = HRC_BUSY; + } + else + { + /* + * We know caller's address so we can process + * more expressions and fill state.node structure.. + */ + session_remote_lookup(remote_emsi->addrs, remote_emsi->anum); + + if( session_check_speed() ) + rc = HRC_LOW_SPEED; + } + } + + /* + * Put EMSI information to log + */ + (void)emsi_logdat(remote_emsi); + + session_remote_log_status(); + + if( rc == HRC_OK ) + { + const long options = conf_options(cf_options); + + /* + * Set inbound directories, ignore errors, + * because we want send mail in any case. + */ + (void)session_set_inbound(); + + /* + * Set protocol that we will use + */ + if( remote_emsi->compcodes.HYD && !(options & OPTIONS_NO_HYDRA) ) + THIS->protocol = PROT_HYDRA; + else if( remote_emsi->compcodes.ZAP && !(options & OPTIONS_NO_ZEDZAP) ) + THIS->protocol = PROT_ZEDZAP; + else if( remote_emsi->compcodes.ZMO && !(options & OPTIONS_NO_ZMODEM) ) + THIS->protocol = PROT_ZMODEM; + else /* NCP */ + { + THIS->protocol = PROT_NOPROT; + rc = HRC_NO_PROTOS; + } + + /* + * Check EMSI flags and set corresponding local HOLD flags + */ + (void)emsi_set_send_options(remote_emsi); + + /* + * Create mail/files queue + */ + session_create_files_queue(remote_emsi->addrs, + remote_emsi->anum); + + /* + * Set FREQ processor status + */ + if( rc == HRC_OK && THIS->protocol != PROT_NOPROT ) + session_set_freqs_status(); + else + state.reqstat = REQS_DISABLED; + } + + /* + * Prepare ``local_emsi'' structure + */ + (void)emsi_set_sysinfo(local_emsi, remote_emsi, rc, THIS->protocol); + + /* + * Send EMSI_DAT packet + */ + if( emsi_send_emsidat(local_emsi) ) + return HRC_OTHER_ERR; + + return rc; +} + +/* + * Do outgoing emsi session + */ +int emsi_outgoing(s_handshake_protocol *THIS) +{ + s_emsi *remote_emsi = NULL; + s_emsi *local_emsi = NULL; + + ASSERT(THIS); + ASSERT(THIS->remote_data); + ASSERT(THIS->local_data); + + remote_emsi = (s_emsi *)THIS->remote_data; + local_emsi = (s_emsi *)THIS->local_data; + + /* + * Set FREQ processor status + */ + session_set_freqs_status(); + + /* + * Prepare ``local_emsi'' structure + */ + (void)emsi_set_sysinfo(local_emsi, NULL, HRC_OK, THIS->protocol); + + /* + * Send EMSI_DAT packet + */ + if( emsi_send_emsidat(local_emsi) ) + return HRC_OTHER_ERR; + + /* + * Receive EMSI_DAT packet + */ + if( emsi_recv_emsidat(remote_emsi) ) + return HRC_OTHER_ERR; + + /* + * Put EMSI information to the log + */ + (void)emsi_logdat(remote_emsi); + + /* + * Make sure expected address was presented + */ + if( session_addrs_check_genuine(remote_emsi->addrs, + remote_emsi->anum, state.node.addr) ) + return HRC_NO_ADDRESS; + + /* + * Check password(s) + */ + if( session_addrs_check(remote_emsi->addrs, remote_emsi->anum, + remote_emsi->passwd, NULL, 0) ) + return HRC_BAD_PASSWD; + + /* + * Lock (create BSY) remote addresses + */ + (void)session_addrs_lock(remote_emsi->addrs, remote_emsi->anum); + + /* + * Set protocol we will use ("options" ignored) + */ + if( remote_emsi->compcodes.HYD && local_emsi->compcodes.HYD ) + THIS->protocol = PROT_HYDRA; + else if( remote_emsi->compcodes.JAN && local_emsi->compcodes.JAN ) + THIS->protocol = PROT_JANUS; + else if( remote_emsi->compcodes.DZA && local_emsi->compcodes.DZA ) + THIS->protocol = PROT_DIRZAP; + else if( remote_emsi->compcodes.ZAP && local_emsi->compcodes.ZAP ) + THIS->protocol = PROT_ZEDZAP; + else if( remote_emsi->compcodes.ZMO && local_emsi->compcodes.ZMO ) + THIS->protocol = PROT_ZMODEM; + else + return HRC_NO_PROTOS; + + /* + * Show remote status (prot/unprot, listed/unlisted) + */ + session_remote_log_status(); + + /* + * Set inbound directories + */ + if( session_set_inbound() ) + return HRC_OTHER_ERR; + + /* + * Check EMSI flags and set corresponding local HOLD flags + */ + (void)emsi_set_send_options(remote_emsi); + + /* + * Create mail/files queue + */ + session_create_files_queue(remote_emsi->addrs, + remote_emsi->anum); + + return HRC_OK; +} + +s_faddr *emsi_remote_address(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_emsi *)THIS->remote_data)->anum > 0 ) + return &((s_emsi *)THIS->remote_data)->addrs[0].addr; + + return NULL; +} + +char *emsi_remote_password(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_emsi *)THIS->remote_data)->passwd[0] ) + return ((s_emsi *)THIS->remote_data)->passwd; + + return NULL; +} + +char *emsi_remote_sysop_name(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_emsi *)THIS->remote_data)->sysop[0] ) + return ((s_emsi *)THIS->remote_data)->sysop; + + return NULL; +} + +char *emsi_remote_system_name(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_emsi *)THIS->remote_data)->sname[0] ) + return ((s_emsi *)THIS->remote_data)->sname; + + return NULL; +} + +char *emsi_remote_location(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_emsi *)THIS->remote_data)->location[0] ) + return ((s_emsi *)THIS->remote_data)->location; + + return NULL; +} + +char *emsi_remote_phone(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_emsi *)THIS->remote_data)->phone[0] ) + return ((s_emsi *)THIS->remote_data)->phone; + + return NULL; +} + +char *emsi_remote_flags(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_emsi *)THIS->remote_data)->flags[0] ) + return ((s_emsi *)THIS->remote_data)->flags; + + return NULL; +} + +char *emsi_remote_mailer(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_emsi *)THIS->remote_data)->m_name[0] ) + return ((s_emsi *)THIS->remote_data)->m_name; + + return NULL; +} + +int emsi_remote_traffic(s_handshake_protocol *THIS, s_traffic *dest) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + ASSERT(dest); + + memset(dest, '\0', sizeof(s_traffic)); + + if( ((s_emsi *)THIS->remote_data)->have_traf + || ((s_emsi *)THIS->remote_data)->have_moh ) + { + dest->netmail_size = ((s_emsi *)THIS->remote_data)->netmail_size; + dest->arcmail_size = ((s_emsi *)THIS->remote_data)->arcmail_size; + dest->files_size = ((s_emsi *)THIS->remote_data)->files_size; + + return 0; + } + + return -1; +} + +s_faddr *emsi_local_address(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->local_data); + + if( ((s_emsi *)THIS->local_data)->anum > 0 ) + return &((s_emsi *)THIS->local_data)->addrs[0].addr; + + return NULL; +} + +char *emsi_local_password(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->local_data); + + if( ((s_emsi *)THIS->local_data)->passwd[0] ) + return ((s_emsi *)THIS->local_data)->passwd; + + return NULL; +} + diff --git a/source/bforce/prot_emsi_misc.c b/source/bforce/prot_emsi_misc.c new file mode 100644 index 0000000..6a868e7 --- /dev/null +++ b/source/bforce/prot_emsi_misc.c @@ -0,0 +1,817 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "version.h" +#include "logger.h" +#include "util.h" +#include "session.h" +#include "prot_emsi.h" + +/* ------------------------------------------------------------------------- */ +/* Add one char $ch to string $src. */ +/* Return pointer to reallocated string */ +/* ------------------------------------------------------------------------- */ +static char *add_char(char *src, char ch) +{ + char *dest; + int len; + + len = src ? strlen(src) : 0; + dest = len ? xrealloc(src, len + 2) : xmalloc(2); + *(dest + len ) = ch; + *(dest + len + 1) = '\0'; + + return(dest); +} + +/* ------------------------------------------------------------------------- */ +/* Add string $add to string $source. Use escaping sequences for */ +/* ']' and '}' characters. Return pointer to reallocated string */ +/* ------------------------------------------------------------------------- */ +static char *add_str(char *source, const char *add) +{ + char *dest; + int len, pos; + + pos = strlen(source); + len = pos + strlen(add) + 1; + dest = (char *)xrealloc(source, len); + + while( *add ) + { + if( (*add == ']') || (*add == '}') ) + { + dest = (char *)xrealloc(dest, ++len); + dest[pos++] = *add; + } + +#ifdef USE_EMSI7BIT + if( !isprint((unsigned char)*add) || (unsigned char)*add > '~' ) +#else + if( !isprint((unsigned char)*add) ) +#endif + { + len += 2; + dest = (char *)xrealloc(dest, len); + sprintf(&dest[pos], "\\%02hd", *(unsigned char*)add); + add += 1; + pos += 3; + } + else + dest[pos++] = *add++; + } + dest[pos] = '\0'; + + return(dest); +} + +/* ------------------------------------------------------------------------- */ +/* Add EMSI-II flag to string $source. Return pointer to reallocated string */ +/* ------------------------------------------------------------------------- */ +static char *add_nflag(char *source, const char *flag, int AKAn) +{ + unsigned char *dest; + unsigned char buf[EMSI_MAXNFLAG+1]; + int len; + + sprintf(buf, "%s%d,", flag, AKAn); + len = strlen(source) + strlen(buf) + 1; + dest = (char *)xrealloc(source, len); + strcat(dest, buf); + + return(dest); +} + +/* ------------------------------------------------------------------------- */ +/* Create emsi subpacket and return pointer to it */ +/* ------------------------------------------------------------------------- */ +char *emsi_createdat(s_emsi *emsi) +{ + int i; + char *tmp = NULL; + char buf[100]; + char abuf[BF_MAXADDRSTR+1]; + + tmp = (char *)xstrcpy("**EMSI_DAT0000"); + + /* {EMSI} indentifier + */ + if( emsi->have_emsi ) + { + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, "EMSI"); + tmp = add_char(tmp, '}'); + + /* our addresses, akas, etc :) */ + tmp = add_char(tmp, '{'); + for( i = 0; i < emsi->anum; i++ ) + { + if( i ) tmp = add_char(tmp, ' '); + tmp = add_str(tmp, ftn_addrstr(abuf, emsi->addrs[i].addr)); + } + tmp = add_char(tmp, '}'); + + /* password if avilable */ + tmp = add_char(tmp, '{'); + if( emsi->passwd[0] ) tmp = add_str(tmp, emsi->passwd); + tmp = add_char(tmp, '}'); + + /* link codes */ + tmp = add_char(tmp, '{'); + if( emsi->linkcodes.N81 ) tmp = add_str(tmp, "8N1,"); + if( emsi->linkcodes.PUP ) tmp = add_str(tmp, "PUP,"); + if( emsi->linkcodes.PUA ) tmp = add_str(tmp, "PUA,"); + if( emsi->linkcodes.NPU ) tmp = add_str(tmp, "NPU,"); + if( emsi->linkcodes.HAT ) tmp = add_str(tmp, "HAT,"); + if( emsi->linkcodes.PMO ) tmp = add_str(tmp, "PMO,"); + if( emsi->linkcodes.NFE ) tmp = add_str(tmp, "NFE,"); + if( emsi->linkcodes.NXP ) tmp = add_str(tmp, "NXP,"); + if( emsi->linkcodes.NRQ ) tmp = add_str(tmp, "NRQ,"); + if( emsi->linkcodes.HNM ) tmp = add_str(tmp, "HNM,"); + if( emsi->linkcodes.HXT ) tmp = add_str(tmp, "HXT,"); + if( emsi->linkcodes.HFE ) tmp = add_str(tmp, "HFE,"); + if( emsi->linkcodes.HRQ ) tmp = add_str(tmp, "HRQ,"); + if( emsi->linkcodes.FNC ) tmp = add_str(tmp, "FNC,"); + if( emsi->linkcodes.RMA ) tmp = add_str(tmp, "RMA,"); + if( emsi->linkcodes.RH1 ) tmp = add_str(tmp, "RH1,"); + for( i = 0; i < emsi->anum; i++ ) + { + if( emsi->addrs[i].flags & EMSI_FLAG_PU ) + tmp = add_nflag(tmp, "PU", i); + if( emsi->addrs[i].flags & EMSI_FLAG_HA ) + tmp = add_nflag(tmp, "HA", i); + if( emsi->addrs[i].flags & EMSI_FLAG_PM ) + tmp = add_nflag(tmp, "PM", i); + if( emsi->addrs[i].flags & EMSI_FLAG_NF ) + tmp = add_nflag(tmp, "NF", i); + if( emsi->addrs[i].flags & EMSI_FLAG_NX ) + tmp = add_nflag(tmp, "NX", i); + if( emsi->addrs[i].flags & EMSI_FLAG_NR ) + tmp = add_nflag(tmp, "NR", i); + if( emsi->addrs[i].flags & EMSI_FLAG_HN ) + tmp = add_nflag(tmp, "HN", i); + if( emsi->addrs[i].flags & EMSI_FLAG_HX ) + tmp = add_nflag(tmp, "HX", i); + if( emsi->addrs[i].flags & EMSI_FLAG_HF ) + tmp = add_nflag(tmp, "HF", i); + if( emsi->addrs[i].flags & EMSI_FLAG_HR ) + tmp = add_nflag(tmp, "HR", i); + } + if( tmp[strlen(tmp+1)] == ',' ) + { + /* replace last ',' character */ + tmp[strlen(tmp+1)] = '}'; + } + else + { + tmp = add_char(tmp, '}'); + } + + /* compatibility_codes */ + tmp = add_char(tmp, '{'); + if( emsi->compcodes.NCP ) tmp = add_str(tmp, "NCP,"); + if( emsi->compcodes.ZMO ) tmp = add_str(tmp, "ZMO,"); + if( emsi->compcodes.ZAP ) tmp = add_str(tmp, "ZAP,"); + if( emsi->compcodes.DZA ) tmp = add_str(tmp, "DZA,"); + if( emsi->compcodes.JAN ) tmp = add_str(tmp, "JAN,"); + if( emsi->compcodes.HYD ) tmp = add_str(tmp, "HYD,"); + if( emsi->compcodes.FRQ ) tmp = add_str(tmp, "FRQ,"); + if( emsi->compcodes.NRQ ) tmp = add_str(tmp, "NRQ,"); + if( emsi->compcodes.ARC ) tmp = add_str(tmp, "ARC,"); + if( emsi->compcodes.XMA ) tmp = add_str(tmp, "XMA,"); + if( emsi->compcodes.FNC ) tmp = add_str(tmp, "FNC,"); + if( emsi->compcodes.EII ) tmp = add_str(tmp, "EII,"); + if( emsi->compcodes.DFB ) tmp = add_str(tmp, "DFB,"); + if( emsi->compcodes.CHT ) tmp = add_str(tmp, "CHT,"); + if( emsi->compcodes.BBS ) tmp = add_str(tmp, "BBS,"); + if( emsi->compcodes.HFR ) tmp = add_str(tmp, "HFR,"); + if( tmp[strlen(tmp+1)] == ',' ) + { + /* replace last ',' character */ + tmp[strlen(tmp+1)] = '}'; + } + else + { + tmp = add_char(tmp, '}'); + } + + /* mailer product code */ + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, emsi->m_pid[0]?emsi->m_pid:"fe"); + tmp = add_char(tmp, '}'); + + /* mailer name */ + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, emsi->m_name[0]?emsi->m_name:"BinkleyForce"); + tmp = add_char(tmp, '}'); + + /* mailer version */ + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, emsi->m_ver[0]?emsi->m_ver:"X.XXX"); + tmp = add_char(tmp, '}'); + + /* mailer serial number */ + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, emsi->m_reg[0]?emsi->m_reg:"Freeware"); + tmp = add_char(tmp, '}'); + } + + /* {IDENT} indentifier + */ + if( emsi->have_ident ) + { + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, "IDENT"); + tmp = add_char(tmp, '}'); + + tmp = add_char(tmp, '{'); + tmp = add_char(tmp, '['); + if( emsi->sname[0] ) tmp = add_str(tmp, emsi->sname); + tmp = add_char(tmp, ']'); + tmp = add_char(tmp, '['); + if( emsi->location[0] ) tmp = add_str(tmp, emsi->location); + tmp = add_char(tmp, ']'); + tmp = add_char(tmp, '['); + if( emsi->sysop[0] ) tmp = add_str(tmp, emsi->sysop); + tmp = add_char(tmp, ']'); + tmp = add_char(tmp, '['); + if( emsi->phone[0] ) tmp = add_str(tmp, emsi->phone); + tmp = add_char(tmp, ']'); + tmp = add_char(tmp, '['); + if( emsi->speed ) + { + sprintf(buf, "%d", emsi->speed); + tmp = add_str(tmp, buf); + } + tmp = add_char(tmp, ']'); + tmp = add_char(tmp, '['); + if( emsi->flags[0] ) tmp = add_str(tmp, emsi->flags); + tmp = add_char(tmp, ']'); + tmp = add_char(tmp, '}'); + } + + /* {TRAF} indentifier + */ + if( emsi->have_traf ) + { + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, "TRAF"); + tmp = add_char(tmp, '}'); + + tmp = add_char(tmp, '{'); + sprintf(buf, "%08lX %08lX", + (long)emsi->netmail_size, (long)emsi->arcmail_size); + tmp = add_str(tmp, buf); + tmp = add_char(tmp, '}'); + } + + /* {MOH#} indentifier + */ + if( emsi->have_moh ) + { + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, "MOH#"); + tmp = add_char(tmp, '}'); + + tmp = add_char(tmp, '{'); + tmp = add_char(tmp, '['); + sprintf(buf, "%08lX", (long)emsi->files_size); + tmp = add_str(tmp, buf); + tmp = add_char(tmp, ']'); + tmp = add_char(tmp, '}'); + } + + /* {OHFR} indentifier + */ + if( emsi->have_ohfr ) + { + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, "OHFR"); + tmp = add_char(tmp, '}'); + + tmp = add_char(tmp, '{'); + if( emsi->oh_time[0] ) + { + tmp = add_str(tmp, emsi->oh_time); + if( emsi->fr_time[0] ) + { + /* send FR time only after OH time */ + tmp = add_char(tmp, ' '); + tmp = add_str(tmp, emsi->fr_time); + } + } + tmp = add_char(tmp, '}'); + } + + /* {TZUTC} indentifier + */ + if( emsi->have_tzutc ) + { + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, "TZUTC"); + tmp = add_char(tmp, '}'); + + tmp = add_char(tmp, '{'); + tmp = add_char(tmp, '['); + sprintf(buf, "+%04d", emsi->tzutc); + tmp = add_str(tmp, buf); + tmp = add_char(tmp, ']'); + tmp = add_char(tmp, '}'); + } + + /* {XDATE} indentifier.. What's the fucking invention :-/ + */ + if( emsi->have_xdatetime ) + { + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, "XDATETIME"); + tmp = add_char(tmp, '}'); + + tmp = add_char(tmp, '{'); + tmp = add_char(tmp, '['); + tmp = add_str(tmp, emsi->xdatetime); + tmp = add_char(tmp, ']'); + tmp = add_char(tmp, '}'); + } + + /* {TRX#} indentifier + */ + if( emsi->have_trx ) + { + tmp = add_char(tmp, '{'); + tmp = add_str(tmp, "TRX#"); + tmp = add_char(tmp, '}'); + + tmp = add_char(tmp, '{'); + tmp = add_char(tmp, '['); + sprintf(buf, "%08lX", (long)emsi->time); + tmp = add_str(tmp, buf); + tmp = add_char(tmp, ']'); + tmp = add_char(tmp, '}'); + } + + /* + * Write total length of + */ + sprintf(buf, "%04hX", (short unsigned)strlen(tmp+14)); + memcpy(tmp+10, buf, 4); + + return(tmp); +} + +/* ------------------------------------------------------------------------- */ +/* Return substring between first pair of $from and $to characters */ +/* Warning: $str destructive */ +/* ------------------------------------------------------------------------- */ +static char *get_field(char **str, char from, char to) +{ + char *dst, *src, *dest = NULL; + int ch; + + src = *str; + + if( *src++ != from ) + return NULL; + + dst = dest = src; + + while( *src ) + { + if( *src == to ) + { + if( *(src+1) == to ) + src++; + else + break; + } + else if( *src == '\\' ) + { + if( *(src+1) == '\\' ) + src++; + else + { + if( strspn(src+1, "0123456789abcdefABCDEF") == 2 ) + { + sscanf(src+1, "%02x", &ch); + *dst++ = (ch & 0xff); + if( ch == ']' ) + *dst++ = ']'; + src += 3; + continue; + } + } + } + *dst++ = *src++; + } + + if( *src == '\0' ) + return NULL; + + *dst = '\0'; + *str = src + 1; + + return dest; +} + +/* ------------------------------------------------------------------------- */ +/* Check $p for EMSI-II link flag $name.. Such flags looks like XXn, */ +/* there n is an AKA number, on success return AKA number else (-1) */ +/* ------------------------------------------------------------------------- */ +static int nflgcmp(const char *p, const char *name) +{ + int AKAn = -1; + + if( (strncmp(p, name, 2) == 0) && + (strspn(p+2, "0123456789") == strlen(p+2)) ) + { + AKAn = atoi(p+2); + } + + return AKAn; +} + +/* ------------------------------------------------------------------------- */ +/* Parse emsi subpacket bracket by bracket. Return zero on success. */ +/* All obtained information put into $emsi structure */ +/* ------------------------------------------------------------------------- */ +int emsi_parsedat(char *emsi_dat, s_emsi *emsi) +{ + int i; + char *tmp, *p, *q, *n; + + while( (tmp=get_field(&emsi_dat, '{', '}')) != NULL ) + { + p = q = n = NULL; + if( strcmp(tmp, "EMSI") == 0 ) + { + emsi->have_emsi = 1; + + /* addresses */ + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + for( p = string_token(p, &n, NULL, 0); p; + p = string_token(NULL, &n, NULL, 0) ) + { + s_faddr addr; + + if( ftn_addrparse(&addr, p, FALSE) ) + log("unparsable address \"%s\" skipped", p); + else + session_addrs_add(&emsi->addrs, &emsi->anum, addr); + } + + if( emsi->anum == 0 ) + { + log("parsable addresses not found"); + return(1); + } + + /* password */ + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( p && *p ) strnxcpy(emsi->passwd, p, sizeof(emsi->passwd)); + + /* link codes */ + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + DEB((D_HSHAKE, "parse_emsidat: link codes: %s", p)); + for( p = strtok(p, ","); p; p=strtok(NULL, ",") ) + { + if( !strcmp(p, "PUP") ) emsi->linkcodes.PUP = 1; + else if( !strcmp(p, "PUA") ) emsi->linkcodes.PUA = 1; + else if( !strcmp(p, "NPU") ) emsi->linkcodes.NPU = 1; + else if( !strcmp(p, "HAT") ) emsi->linkcodes.HAT = 1; + else if( !strcmp(p, "PMO") ) emsi->linkcodes.PMO = 1; + else if( !strcmp(p, "NFE") ) emsi->linkcodes.NFE = 1; + else if( !strcmp(p, "NXP") ) emsi->linkcodes.NXP = 1; + else if( !strcmp(p, "NRQ") ) emsi->linkcodes.NRQ = 1; + else if( !strcmp(p, "HNM") ) emsi->linkcodes.HNM = 1; + else if( !strcmp(p, "HXT") ) emsi->linkcodes.HXT = 1; + else if( !strcmp(p, "HFE") ) emsi->linkcodes.HFE = 1; + else if( !strcmp(p, "HRQ") ) emsi->linkcodes.HRQ = 1; + else if( !strcmp(p, "FNC") ) emsi->linkcodes.FNC = 1; + else if( !strcmp(p, "RMA") ) emsi->linkcodes.RMA = 1; + else if( !strcmp(p, "RH1") ) emsi->linkcodes.RH1 = 1; + /* check EMSI-II address dependend flags */ + else if( ((i=nflgcmp(p, "HA")) >= 0) && (i < emsi->anum) ) + emsi->addrs[i].flags |= EMSI_FLAG_HA; + else if( ((i=nflgcmp(p, "PM")) >= 0) && (i < emsi->anum) ) + emsi->addrs[i].flags |= EMSI_FLAG_PM; + else if( ((i=nflgcmp(p, "NF")) >= 0) && (i < emsi->anum) ) + emsi->addrs[i].flags |= EMSI_FLAG_NF; + else if( ((i=nflgcmp(p, "NX")) >= 0) && (i < emsi->anum) ) + emsi->addrs[i].flags |= EMSI_FLAG_NX; + else if( ((i=nflgcmp(p, "NR")) >= 0) && (i < emsi->anum) ) + emsi->addrs[i].flags |= EMSI_FLAG_NR; + else if( ((i=nflgcmp(p, "HN")) >= 0) && (i < emsi->anum) ) + emsi->addrs[i].flags |= EMSI_FLAG_HN; + else if( ((i=nflgcmp(p, "HX")) >= 0) && (i < emsi->anum) ) + emsi->addrs[i].flags |= EMSI_FLAG_HX; + else if( ((i=nflgcmp(p, "HF")) >= 0) && (i < emsi->anum) ) + emsi->addrs[i].flags |= EMSI_FLAG_HF; + else if( ((i=nflgcmp(p, "HR")) >= 0) && (i < emsi->anum) ) + emsi->addrs[i].flags |= EMSI_FLAG_HR; + } + + /* compatibility codes */ + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + DEB((D_HSHAKE, "parse_emsidat: compatibility codes: %s", p)); + for( p = strtok(p, ","); p; p=strtok(NULL, ",") ) + { + if( !strcmp(p, "ZMO") ) emsi->compcodes.ZMO = 1; + else if( !strcmp(p, "ZAP") ) emsi->compcodes.ZAP = 1; + else if( !strcmp(p, "DZA") ) emsi->compcodes.DZA = 1; + else if( !strcmp(p, "JAN") ) emsi->compcodes.JAN = 1; + else if( !strcmp(p, "HYD") ) emsi->compcodes.HYD = 1; + else if( !strcmp(p, "NCP") ) emsi->compcodes.NCP = 1; + else if( !strcmp(p, "NRQ") ) emsi->compcodes.NRQ = 1; + else if( !strcmp(p, "ARC") ) emsi->compcodes.ARC = 1; + else if( !strcmp(p, "XMA") ) emsi->compcodes.XMA = 1; + else if( !strcmp(p, "FNC") ) emsi->compcodes.FNC = 1; + else if( !strcmp(p, "EII") ) emsi->compcodes.EII = 1; + else if( !strcmp(p, "CHT") ) emsi->compcodes.CHT = 1; + else if( !strcmp(p, "BBS") ) emsi->compcodes.BBS = 1; + else if( !strcmp(p, "HFR") ) emsi->compcodes.HFR = 1; + } + + /* mailer information */ + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( p && *p ) strnxcpy(emsi->m_pid, p, sizeof(emsi->m_pid)); + + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( p && *p ) strnxcpy(emsi->m_name, p, sizeof(emsi->m_name)); + + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( p && *p ) strnxcpy(emsi->m_ver, p, sizeof(emsi->m_ver)); + + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( p && *p ) strnxcpy(emsi->m_reg, p, sizeof(emsi->m_reg));; + } + else if( strcmp(tmp, "IDENT") == 0 ) + { + emsi->have_ident = 1; + + if( (tmp=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( (p=get_field(&tmp, '[', ']')) == NULL ) return(1); + if( p && *p ) strnxcpy(emsi->sname, p, sizeof(emsi->sname)); + if( (p=get_field(&tmp, '[', ']')) == NULL ) return(1); + if( p && *p ) strnxcpy(emsi->location, p, sizeof(emsi->location)); + if( (p=get_field(&tmp, '[', ']')) == NULL ) return(1); + if( p && *p ) strnxcpy(emsi->sysop, p, sizeof(emsi->sysop)); + if( (p=get_field(&tmp, '[', ']')) == NULL ) return(1); + if( p && *p ) strnxcpy(emsi->phone, p, sizeof(emsi->phone));; + if( (p=get_field(&tmp, '[', ']')) == NULL ) return(1); + if( p && *p ) sscanf(p, "%d", &emsi->speed); + if( (p=get_field(&tmp, '[', ']')) == NULL ) return(1); + if( p && *p ) strnxcpy(emsi->flags, p, sizeof(emsi->flags)); + } + else if( strcmp(tmp, "TRX#") == 0 ) + { + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( (p=get_field(&p, '[', ']')) == NULL ) return(1); + if( sscanf(p, "%08lx", &emsi->time) == 1 ) + { + emsi->have_trx = 1; + } + else + { + log("Bad TRX# entry \"%s\"", p); + } + } + else if( strcmp(tmp, "TRAF") == 0 ) + { + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( p && *p ) + { + if( sscanf(p, "%08X %08X", &emsi->netmail_size, &emsi->arcmail_size) == 2 ) + { + emsi->have_traf = 1; + } + else + { + log("Bad TRAF entry \"%s\"", p); + } + } + } + else if( strcmp(tmp, "MOH#") == 0 ) + { + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( (p=get_field(&p, '[', ']')) == NULL ) return(1); + if( p && *p ) + { + if( sscanf(p, "%08X", &emsi->files_size) == 1 ) + { + emsi->have_moh = 1; + } + else + { + log("Bad MOH# entry \"%s\"", p); + } + } + else + { + log("Bad MOH# entry \"%s\"", p); + } + } + else if( strcmp(tmp, "OHFR") == 0 ) + { + emsi->have_ohfr = 1; + + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + + q = p; + while( *q && !isspace(*q) ) q++; + if( *q ) *q++ = '\0'; + if( *p ) strnxcpy(emsi->oh_time, p, sizeof(emsi->oh_time)); + + while( *q && isspace(*q) ) q++; + if( *q ) strnxcpy(emsi->fr_time, q, sizeof(emsi->fr_time)); + } + else if( strcmp(tmp, "XDATETIME") == 0 ) + { + emsi->have_xdatetime = 1; + + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( (p=get_field(&p, '[', ']')) == NULL ) return(1); + if( *p ) strnxcpy(emsi->xdatetime, p, sizeof(emsi->xdatetime)); + } + else if( strcmp(tmp, "TZUTC") == 0 ) + { + emsi->have_tzutc = 1; + + if( (p=get_field(&emsi_dat, '{', '}')) == NULL ) return(1); + if( (p=get_field(&p, '[', ']')) == NULL ) return(1); + } + else + { + strnxcat(emsi->addons, "{", sizeof(emsi->addons)); + strnxcat(emsi->addons, tmp, sizeof(emsi->addons)); + strnxcat(emsi->addons, "}", sizeof(emsi->addons)); + } + } /* end of while */ + + return(0); +} + +void emsi_logdat(s_emsi *emsi) +{ + int i; + char abuf[BF_MAXADDRSTR+1]; + char buf[64]; + + if( emsi->have_emsi ) + { + if( emsi->anum ) + { + for( i = 0; i < emsi->anum; i++ ) + { + if( emsi->addrs[i].busy ) + log(" Address : %s (Busy)", ftn_addrstr(abuf, emsi->addrs[i].addr)); + else + log(" Address : %s", ftn_addrstr(abuf, emsi->addrs[i].addr)); + } + } + else + { + log(" Address : "); + } + } + + if( emsi->have_ident ) + { + if( emsi->sname[0] && emsi->phone[0] ) + log(" System : %s (%s)", + string_printable(emsi->sname), + string_printable(emsi->phone)); + else if( emsi->sname[0] ) + log(" System : %s", + string_printable(emsi->sname)); + else if( emsi->phone[0] ) + log(" Phone : %s", + string_printable(emsi->phone)); + } + + if( emsi->have_emsi ) + { + char flags[128]; + *flags = '\0'; + + if( emsi->linkcodes.PUP ) + strcat(flags, "PUP,"); + if( emsi->linkcodes.NPU ) + strcat(flags, "NPU,"); + if( emsi->linkcodes.HAT ) + strcat(flags, "HAT,"); + if( emsi->linkcodes.NRQ || emsi->compcodes.NRQ ) + strcat(flags, "NRQ,"); + if( emsi->linkcodes.HXT ) + strcat(flags, "HXT,"); + if( emsi->linkcodes.HRQ ) + strcat(flags, "HRQ,"); + if( emsi->linkcodes.FNC || emsi->compcodes.FNC ) + strcat(flags, "FNC,"); + if( emsi->compcodes.FRQ ) + strcat(flags, "FRQ,"); + if( emsi->compcodes.EII ) + strcat(flags, "EII,"); + if( emsi->compcodes.CHT ) + strcat(flags, "CHT,"); + if( emsi->compcodes.BBS ) + strcat(flags, "BBS,"); + if( emsi->compcodes.HFR ) + strcat(flags, "HFR,"); + + if( *flags ) + { + flags[strlen(flags)-1] = '\0'; + log(" Options : %s", flags); + } + } + +#ifdef BFORCE_LOG_PASSWD + if( emsi->have_emsi ) + { + if( emsi->passwd[0] ) + log(" Password : %s", string_printable(emsi->passwd)); + } +#endif + + if( emsi->have_ident ) + { + if( emsi->sysop[0] && emsi->location[0] ) + log(" SysOp : %s from %s", + string_printable(emsi->sysop), + string_printable(emsi->location)); + else if( emsi->sysop[0] ) + log(" SysOp : %s", + string_printable(emsi->sysop)); + else if( emsi->location[0] ) + log(" Location : %s", + string_printable(emsi->location)); + + if( emsi->flags[0] && emsi->speed ) + log(" Flags : %d,%s", + emsi->speed, string_printable(emsi->flags)); + else if( emsi->flags[0] ) + log(" Flags : %s", + string_printable(emsi->flags)); + else if( emsi->speed ) + log(" Speed : %d", emsi->speed); + } + + if( emsi->have_emsi ) + { + if( emsi->m_name[0] || emsi->m_pid[0] + || emsi->m_ver[0] || emsi->m_reg ) + { + log(" Mailer : %s [%s] %s/%s", + emsi->m_name[0] ? string_printable(emsi->m_name) : "?", + emsi->m_pid[0] ? string_printable(emsi->m_pid) : "?", + emsi->m_ver[0] ? string_printable(emsi->m_ver) : "?", + emsi->m_reg[0] ? string_printable(emsi->m_reg) : "?"); + } + } + + if( emsi->have_trx ) + { + log(" Time : %s", time_string_long(buf, sizeof(buf), gmttolocal(emsi->time))); + } + + if( emsi->have_xdatetime ) + { + log(" XDATETIME : %s", string_printable(emsi->xdatetime)); + } + + if( emsi->have_ohfr ) + { + log(" OHFR : \"%s\" and \"%s\"", + string_printable(emsi->oh_time), + string_printable(emsi->fr_time)); + } + + if( emsi->have_traf ) + { + log(" TRAF : netmail %ldb, arcmail %ldb", + emsi->netmail_size, emsi->arcmail_size); + } + + if( emsi->have_moh ) + { + log(" #MOH : files %ldb", emsi->files_size); + } + + if( emsi->addons[0] ) + { + log("EMSI addon : %s", + string_printable(emsi->addons)); + } +} diff --git a/source/bforce/prot_hydra.c b/source/bforce/prot_hydra.c new file mode 100644 index 0000000..cfb4cf0 --- /dev/null +++ b/source/bforce/prot_hydra.c @@ -0,0 +1,2136 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "session.h" +#include "outbound.h" +#include "io.h" +#include "prot_common.h" + +typedef enum hydra_pkttype { + HPKT_EXIT = -3, + HPKT_JUNK = -2, + HPKT_NONE = -1, + HPKT_START = 'A', + HPKT_INIT = 'B', + HPKT_INITACK = 'C', + HPKT_FINFO = 'D', + HPKT_FINFOACK = 'E', + HPKT_DATA = 'F', + HPKT_DATAACK = 'G', + HPKT_RPOS = 'H', + HPKT_EOF = 'I', + HPKT_EOFACK = 'J', + HPKT_END = 'K', + HPKT_IDLE = 'L', + HPKT_DEVDATA = 'M', + HPKT_DEVDACK = 'N', + HPKT_MIN = HPKT_START, + HPKT_MAX = HPKT_DEVDACK +} e_hydra_pkttype; + +typedef enum hydra_char { + HCHR_PKTEND = 'a', + HCHR_BINPKT = 'b', + HCHR_HEXPKT = 'c', + HCHR_ASCPKT = 'd', + HCHR_UUEPKT = 'e', + HCHR_MIN = HCHR_PKTEND, + HCHR_MAX = HCHR_UUEPKT +} e_hydra_char; + +typedef enum hydra_txstate { + HTX_DONE, + HTX_START, + HTX_SWAIT, + HTX_INIT, + HTX_INITACK, + HTX_RINIT, + HTX_NextFile, + HTX_ToFName, + HTX_FINFO, + HTX_FINFOACK, + HTX_DATA, + HTX_SkipFile, + HTX_DATAACK, + HTX_XWAIT, + HTX_EOF, + HTX_EOFACK, + HTX_REND, + HTX_END, + HTX_ENDACK, + HTX_Abort +} e_hydra_txstate; + +typedef enum hydra_rxstate { + HRX_DONE, + HRX_INIT, + HRX_FINFO, + HRX_DATA, + HRX_RPOS, + HRX_RPosAck, + HRX_Skip, + HRX_SkipAck +} e_hydra_rxstate; + +char *hydra_pkttype_names[] = +{ + "HPKT_START", + "HPKT_INIT", + "HPKT_INITACK", + "HPKT_FINFO", + "HPKT_FINFOACK", + "HPKT_DATA", + "HPKT_DATAACK", + "HPKT_RPOS", + "HPKT_EOF", + "HPKT_EOFACK", + "HPKT_END", + "HPKT_IDLE", + "HPKT_DEVDATA" +}; + +char *hydra_char_names[] = +{ + "HCHR_PKTEND", + "HCHR_BINPKT", + "HCHR_HEXPKT", + "HCHR_ASCPKT", + "HCHR_UUEPKT" +}; + +char *hydra_txstate_names[] = +{ + "HTX_DONE", + "HTX_START", + "HTX_SWAIT", + "HTX_INIT", + "HTX_INITACK", + "HTX_RINIT", + "HTX_NextFile", + "HTX_ToFName", + "HTX_FINFO", + "HTX_FINFOACK", + "HTX_DATA", + "HTX_SkipFile", + "HTX_DATAACK", + "HTX_XWAIT", + "HTX_EOF", + "HTX_EOFACK", + "HTX_REND", + "HTX_END", + "HTX_ENDACK", + "HTX_Abort" +}; + +char *hydra_rxstate_names[] = +{ + "HRX_DONE", + "HRX_INIT", + "HRX_FINFO", + "HRX_DATA", + "HRX_RPOS", + "HRX_RPosAck", + "HRX_Skip", + "HRX_SkipAck" +}; + +#define HYDRA_DLE ('X' - '@') +#define HYDRA_MINBLKLEN 64 +#define HYDRA_MAXBLKLEN 2048 +#define HYDRA_OVERHEAD 8 +#define HYDRA_MAXDATALEN (HYDRA_MAXBLKLEN + HYDRA_OVERHEAD + 5) +#define HYDRA_MAXPKTLEN ((HYDRA_MAXBLKLEN + HYDRA_OVERHEAD + 5) * 3) +#define HYDRA_BUFLEN (HYDRA_MAXPKTLEN + 16) +#define HYDRA_PKTPREFIX 31 + +#define HOPT_XONXOFF 0x00000001L +#define HOPT_TELENET 0x00000002L +#define HOPT_CTLCHRS 0x00000004L +#define HOPT_HIGHCTL 0x00000008L +#define HOPT_HIGHBIT 0x00000010L +#define HOPT_CANBRK 0x00000020L +#define HOPT_CANASC 0x00000040L +#define HOPT_CANUUE 0x00000080L +#define HOPT_CRC32 0x00000100L +#define HOPT_DEVICE 0x00000200L +#define HOPT_FPT 0x00000400L + +/* What we can do */ +#define HYDRA_CANOPT (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT | HOPT_CANASC | HOPT_CANUUE | HOPT_CRC32) +/* Vital options if we ask for any; abort if other side doesn't support them */ +#define HYDRA_NECOPT (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT | HOPT_CANBRK) +/* Default options */ +#define HYDRA_DEFOPT (0L | HOPT_CRC32) +/* rxoptions during init (needs to handle ANY link yet unknown at that point */ +#define HYDRA_RXIOPT (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT) +/* ditto, but this time txoptions */ +#define HYDRA_TXIOPT (HOPT_XONXOFF | HOPT_TELENET | HOPT_CTLCHRS | HOPT_HIGHCTL | HOPT_HIGHBIT) + +#define HYDRA_UUENC(c) (((c) & 0x3f) + '!') +#define HYDRA_UUDEC(c) (((c) - '!') & 0x3f) +#define HYDRA_ISUUE(c) ((c) > ' ' && (c) < 'a') + + +#ifdef DEBUG +#define HYDRA_TXSTATE(c) (hydra_txstate_names[c]) +#define HYDRA_RXSTATE(c) (hydra_rxstate_names[c]) +#define HYDRA_PKTNAME(c) ((c < HPKT_MIN || c > HPKT_MAX) ? "Out of range" : hydra_pkttype_names[c - HPKT_MIN]) +#define HYDRA_CHRNAME(c) ((c < HCHR_MIN || c > HCHR_MAX) ? "Out of range" : hydra_char_names[c - HCHR_MIN]) +#else +#define HYDRA_TXSTATE(c) ("No debug information") +#define HYDRA_RXSTATE(c) ("No debug information") +#define HYDRA_PKTNAME(c) ("No debug information") +#define HYDRA_CHRNAME(c) ("No debug information") +#endif + +typedef struct { + const char *str; + unsigned long val; + size_t len; +} s_hydraflag; + +typedef struct { + bool sent; + enum hydra_pkttype type; + char *data; + size_t size; +} s_hydrapkt; + +s_hydraflag hydraflags[] = +{ + { "XON", HOPT_XONXOFF, 3 }, + { "TLN", HOPT_TELENET, 3 }, + { "CTL", HOPT_CTLCHRS, 3 }, + { "HIC", HOPT_HIGHCTL, 3 }, + { "HI8", HOPT_HIGHBIT, 3 }, + { "BRK", HOPT_CANBRK, 3 }, + { "ASC", HOPT_CANASC, 3 }, + { "UUE", HOPT_CANUUE, 3 }, + { "C32", HOPT_CRC32, 3 }, + { "DEV", HOPT_DEVICE, 3 }, + { "FPT", HOPT_FPT, 3 }, + { NULL , 0x0L, 0 } +}; + +typedef struct { + char *oencbuf; /* Encoded data for sending */ + char *oencptr; /* Pointer to the UNSENT encoded data */ + int oencpos; /* Total length of encoded data */ + char *obuf; + int lastchar; /* Last character we sent */ + + char *iencbuf; + char *iencptr; + bool iencrcv; /* Flag: we are receiving packet now */ + int iencfmt; /* Format of packet we are receiving */ + int idlecnt; /* Counter for received HYDRA_DLE characters */ + char *ibuf; /* Decoded packet */ + int isize; /* Decoded packet size */ + + int timeout_send; + int timeout_recv; + int timeout_dead; + + int send_block_size; + int send_good_blocks; /* Count sent blocks for current block size */ + int recv_block_size; + + unsigned long txwindow; + unsigned long rxwindow; + + unsigned long options; + unsigned long rxoptions; + unsigned long txoptions; + + long recv_rpos_id; + long send_rpos_id; + + bool batchesdone; /* It is not our first batch? */ + + s_hydrapkt *pktqueue; + int n_pkts; +} s_hydrainfo; + +static char *hydra_putlong(char *buf, long val) +{ + buf[0] = ( ((unsigned long) val) ) & 0xff; + buf[1] = ( ((unsigned long) val) >> 8 ) & 0xff; + buf[2] = ( ((unsigned long) val) >> 16 ) & 0xff; + buf[3] = ( ((unsigned long) val) >> 24 ) & 0xff; + + return buf; +} + +static char *hydra_putword(char *buf, int val) +{ + buf[0] = ( ((unsigned int) val) ) & 0xff; + buf[1] = ( ((unsigned int) val) >> 8 ) & 0xff; + + return buf; +} + +static long hydra_getlong(const char *buf) +{ + return ( (unsigned long) ((unsigned char) buf[0]) ) + | ( (unsigned long) ((unsigned char) buf[1]) << 8 ) + | ( (unsigned long) ((unsigned char) buf[2]) << 16 ) + | ( (unsigned long) ((unsigned char) buf[3]) << 24 ); +} + +static int hydra_getword(const char *buf) +{ + return ( (unsigned int) ((unsigned char) buf[0]) ) + | ( (unsigned int) ((unsigned char) buf[1]) << 8 ); +} + +static char *hydra_putflags(char *buf, unsigned long flags, size_t szbuf) +{ + int i; + size_t szused = 0; + + *buf = '\0'; + + for( i = 0; hydraflags[i].str; i++ ) + { + if( hydraflags[i].val & flags ) + { + if( szused + hydraflags[i].len + 2 > szbuf ) + { + ASSERT_MSG(); + break; + } + else if( szused > 0 ) + { + *buf++ = ','; + ++szused; + } + strcpy(buf, hydraflags[i].str); + buf += hydraflags[i].len; + szused += hydraflags[i].len; + } + } + + return buf; +} + +static unsigned long hydra_getflags(char *buf) +{ + int i; + char *p; + unsigned long result = 0L; + + for( p = strtok(buf, ","); p; p = strtok(NULL, ",") ) + { + for( i = 0; hydraflags[i].str; i++ ) + { + if( strcmp(p, hydraflags[i].str) == 0 ) + { + result |= hydraflags[i].val; + break; + } + } + } + + return result; +} + +#ifdef DEBUG +static void hydra_pktdebug(bool send, s_hydrainfo *hi, const char *data, + e_hydra_pkttype pkttype, e_hydra_char format, + bool crc32, size_t sz) +{ + char *p; + + DEB((D_PROT, "hydra_pktdebug: %s packet '%s' #%d (len=%ld, format='%s', crc=%d)", + send ? "<-" : "->", HYDRA_PKTNAME(pkttype), pkttype, sz, + HYDRA_CHRNAME(format), crc32 ? 32 : 16)); + + /* + * For some packet types we will log more information + */ + switch(pkttype) { + case HPKT_FINFO: + DEB((D_PROT, "hydra_pktdebug: FINFO \"%s\"", + p = string_printable_buffer(data, sz))); + if( p ) free(p); + break; + case HPKT_FINFOACK: + if( data[0] == '\0' ) + DEB((D_PROT, "hydra_pktdebug: FINFOACK (End Of Batch)")); + else + DEB((D_PROT, "hydra_pktdebug: FINFOACK (offset=%ld)", + (long)hydra_getlong(data))); + break; + case HPKT_DATA: + DEB((D_PROT, "hydra_pktdebug: DATA (offset=%ld, length=%ld)", + (long)hydra_getlong(data), (long)(sz - 5))); + break; + case HPKT_DATAACK: + DEB((D_PROT, "hydra_pktdebug: DATAACK (offset=%ld)", + hydra_getlong(data))); + break; + case HPKT_RPOS: + DEB((D_PROT, "hydra_pktdebug: RPOS (pos=%ld, blklen=%d, syncid=%ld)", + hydra_getlong(data), hydra_getword(data+4), + hydra_getlong(data+6))); + break; + case HPKT_EOF: + DEB((D_PROT, "hydra_pktdebug: EOF (offset=%ld)", + hydra_getlong(data))); + break; + default: + /* Avoid warnings about unhandled values */ + break; + } +} +#endif /* DEBUG */ + +static char *hydra_putbinbyte(s_hydrainfo *hi, char *buf, unsigned char c) +{ + unsigned char n = c; + + if( hi->txoptions & HOPT_HIGHCTL ) + n &= 0x7f; + + if( (n == HYDRA_DLE) + || ((hi->txoptions & HOPT_XONXOFF) && ((n == XON) || (n == XOFF))) + || ((hi->txoptions & HOPT_TELENET) && (n == '\r') && (hi->lastchar == '@')) + || ((hi->txoptions & HOPT_CTLCHRS) && ((n < 32) || (n == 127))) ) + { + *buf++ = HYDRA_DLE; + c ^= 0x40; + } + + *buf++ = c; + hi->lastchar = n; + + return buf; +} + +static char *hydra_puthexbyte(char *buf, unsigned char c) +{ + static const char hexdigit[] = "0123456789abcdef"; + + if( c & 0x80 ) + { + *buf++ = '\\'; + *buf++ = hexdigit[(c >> 4) & 0x0f]; + *buf++ = hexdigit[(c ) & 0x0f]; + } + else if( (c < 32) || (c == 127) ) + { + *buf++ = HYDRA_DLE; + *buf++ = c ^ 0x40; + } + else if( c == '\\' ) + { + *buf++ = '\\'; + *buf++ = '\\'; + } + else + *buf++ = c; + + return buf; +} + +static char *hydra_putascblock(s_hydrainfo *hi, char *buf, char *src, size_t szsrc) +{ + int ch = 0; + int bitshift = 0; + + for( ; szsrc > 0; --szsrc, ++src ) + { + ch |= ((unsigned char)(*src) << bitshift); + + buf = hydra_putbinbyte(hi, buf, ((unsigned char)(ch) & 0x7f)); + ch >>= 7; + + if( ++bitshift >= 7 ) + { + buf = hydra_putbinbyte(hi, buf, ((unsigned char)(ch) & 0x7f)); + ch = bitshift = 0; + } + } + + if( bitshift > 0 ) + buf = hydra_putbinbyte(hi, buf, ((unsigned char)(ch) & 0x7f)); + + return buf; +} + +static char *hydra_putuueblock(char *buf, char *src, size_t szsrc) +{ + for( ; szsrc >= 3; src += 3, szsrc -= 3 ) + { + *buf++ = HYDRA_UUENC(src[0] >> 2); + *buf++ = HYDRA_UUENC(((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)); + *buf++ = HYDRA_UUENC(((src[1] << 2) & 0x3c) | ((src[2] >> 6) & 0x03)); + *buf++ = HYDRA_UUENC(src[2] & 0x3f); + } + + if( szsrc > 0 ) + { + *buf++ = HYDRA_UUENC(src[0] >> 2); + *buf++ = HYDRA_UUENC(((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)); + if( szsrc == 2 ) + *buf++ = HYDRA_UUENC((src[1] << 2) & 0x3c); + } + + return buf; +} + +static char *hydra_putpkt(s_hydrainfo *hi, char *dst, char *src, size_t szsrc, + enum hydra_pkttype pkttype) +{ + enum hydra_char format; + char *obuf; + int pos; + + switch(pkttype) { + case HPKT_START: + case HPKT_INIT: + case HPKT_INITACK: + case HPKT_END: + case HPKT_IDLE: + format = HCHR_HEXPKT; + break; + default: + if( hi->txoptions & HOPT_HIGHBIT ) + { + if( (hi->txoptions & HOPT_CTLCHRS) + && (hi->txoptions & HOPT_CANUUE ) ) + format = HCHR_UUEPKT; + else if( hi->txoptions & HOPT_CANASC ) + format = HCHR_ASCPKT; + else + format = HCHR_HEXPKT; + } + else + format = HCHR_BINPKT; + } /* end of switch */ + +#ifdef DEBUG + hydra_pktdebug(TRUE, hi, src, pkttype, format, + (format != HCHR_HEXPKT && (hi->txoptions & HOPT_CRC32)), szsrc); +#endif + + src[szsrc++] = pkttype; + + if( format != HCHR_HEXPKT && (hi->txoptions & HOPT_CRC32) ) + { + unsigned long crc32 = ~getcrc32ccitt(src, szsrc); + + src[szsrc++] = (((unsigned char) (crc32 )) & 0xff); + src[szsrc++] = (((unsigned char) (crc32 >> 8 )) & 0xff); + src[szsrc++] = (((unsigned char) (crc32 >> 16)) & 0xff); + src[szsrc++] = (((unsigned char) (crc32 >> 24)) & 0xff); + } + else + { + unsigned short crc16 = ~getcrc16ccitt(src, szsrc); + + src[szsrc++] = (((unsigned char) (crc16 )) & 0xff); + src[szsrc++] = (((unsigned char) (crc16 >> 8)) & 0xff); + } + + obuf = dst; + *obuf++ = HYDRA_DLE; + *obuf++ = format; + + switch(format) { + case HCHR_BINPKT: + for( pos = 0; pos < szsrc; pos++ ) + obuf = hydra_putbinbyte(hi, obuf, *src++); + break; + case HCHR_HEXPKT: + for( pos = 0; pos < szsrc; pos++ ) + obuf = hydra_puthexbyte(obuf, *src++); + break; + case HCHR_ASCPKT: + obuf = hydra_putascblock(hi, obuf, src, szsrc); + break; + case HCHR_UUEPKT: + obuf = hydra_putuueblock(obuf, src, szsrc); + break; + default: + ASSERT(0); + } + + *obuf++ = HYDRA_DLE; + *obuf++ = HCHR_PKTEND; + + if( pkttype != HPKT_DATA && format != HCHR_BINPKT ) + { + *obuf++ = '\r'; + *obuf++ = '\n'; + } + + return obuf; +} + +void hydra_queuepkt(s_hydrainfo *hi, char *data, size_t szdata, + enum hydra_pkttype pkttype) +{ + char *endptr = NULL; + char *buffer = NULL; + size_t pktlen; + + ASSERT(szdata <= HYDRA_MAXBLKLEN); + + if( data && szdata > 0 ) + { + buffer = xmalloc(HYDRA_BUFLEN); + endptr = hydra_putpkt(hi, buffer, data, szdata, pkttype); + pktlen = endptr - buffer; + + /* Check for buffer overflow */ + ASSERT(pktlen <= HYDRA_BUFLEN); + + /* Release unused memory */ + buffer = xrealloc(buffer, endptr - buffer); + } + else + { + buffer = xmalloc(HYDRA_OVERHEAD*3); + endptr = hydra_putpkt(hi, buffer, hi->obuf, 0, pkttype); + pktlen = endptr - buffer; + + /* Check for buffer overflow */ + ASSERT(pktlen <= (HYDRA_OVERHEAD*3)); + } + + /* Add new entry to the queue */ + hi->pktqueue = xrealloc(hi->pktqueue, sizeof(s_hydrapkt)*(hi->n_pkts + 1)); + memset(&hi->pktqueue[hi->n_pkts], '\0', sizeof(s_hydrapkt)); + + /* Set packet data */ + hi->pktqueue[hi->n_pkts].sent = FALSE; + hi->pktqueue[hi->n_pkts].type = pkttype; + hi->pktqueue[hi->n_pkts].data = buffer; + hi->pktqueue[hi->n_pkts].size = pktlen; + hi->n_pkts++; + + DEB((D_PROT, "hydra_queuepkt: queue packet '%s' #%d, %ld bytes", + HYDRA_PKTNAME(pkttype), (int)pkttype, (long)(endptr - buffer))); +} + +static int hydra_buffer_packet(s_hydrainfo *hi, s_hydrapkt *pkt) +{ + /* Is there space for the new pkt? */ + if( hi->oencpos + pkt->size > HYDRA_BUFLEN ) return 1; + + if( pkt->data ) + { + DEB((D_PROT, "hydra_buffer_packet: buffer packet '%s' #%d, %ld bytes", + HYDRA_PKTNAME(pkt->type), (int)pkt->type, (long)pkt->size)); + memcpy(hi->oencbuf + hi->oencpos, pkt->data, pkt->size); + hi->oencpos += pkt->size; + free(pkt->data); + pkt->data = NULL; + } + + return 0; +} + +static int hydra_send(s_hydrainfo *hi) +{ + int i; + + if( hi->oencpos == 0 && hi->pktqueue ) + { + /* + * Buffer is empty and there are unsent packets + */ + for( i = 0; i < hi->n_pkts; i++ ) + { + if( hi->pktqueue[i].sent == FALSE ) + { + if( hydra_buffer_packet(hi, &hi->pktqueue[i]) ) + break; + else + hi->pktqueue[i].sent = TRUE; + } + } + /* If the packet queue is empty, free it */ + if( i >= hi->n_pkts ) + { + if( hi->pktqueue ) + { + free(hi->pktqueue); + hi->pktqueue = NULL; + } + hi->n_pkts = 0; + } + } + + /* Send buffered data */ + if( hi->oencpos ) + { + int n = tty_write(hi->oencptr, hi->oencpos); + + if( n >= hi->oencpos ) + { + hi->oencptr = hi->oencbuf; + hi->oencpos = 0; + } + else if( n > 0 ) + { + hi->oencptr += n; + hi->oencpos -= n; + } + else + return -1; + } + + return 0; +} + +static char *hydra_getbinblock(char *dst, size_t szdst, char *src, size_t szsrc) +{ + if( szsrc > szdst ) + { + log("Hydra: BIN packet buffer overflow detected"); + return NULL; + } + + memcpy(dst, src, szsrc); + + return dst + szsrc; +} + +static char *hydra_gethexblock(char *dst, size_t szdst, char *src, size_t szsrc) +{ + char *in = src; + char *out = dst; + char *enddst = dst + szdst - 1; + char *endsrc = src + szsrc - 1; + int hex1 = 0; + int hex2 = 0; + + while( in <= endsrc && out <= enddst ) + { + if( (*in == '\\') && (*++in != '\\') ) + { + hex1 = (unsigned char)(*in++); + hex2 = (unsigned char)(*in++); + + if( (hex1 -= '0') > 9 ) + hex1 -= ('a' - ':'); + if( (hex2 -= '0') > 9 ) + hex2 -= ('a' - ':'); + + *out++ = ((hex1 << 4) | hex2) & 0xff; + } + else + *out++ = *in++; + } + + if( out > enddst ) + log("Hydra: HEX decoder buffer overflow detected"); + + return out; +} + +static char *hydra_getascblock(char *dst, size_t szdst, char *src, size_t szsrc) +{ + char *in = src; + char *out = dst; + char *enddst = dst + szdst - 1; + char *endsrc = src + szsrc - 1; + int n = 0; + int c = 0; + + while( (in <= endsrc) && (out <= enddst) ) + { + c |= (((unsigned char)(*in) & 0x7f) << n); + + if( (n += 7) >= 8 ) + { + *out++ = (unsigned char)(c & 0xff); + c >>= 8; + n -= 8; + } + ++in; + } + + if( out > enddst ) + log("Hydra: ASC decoder buffer overflow detected"); + + return out; +} + +static char *hydra_getuueblock(char *dst, size_t szdst, char *src, size_t szsrc) +{ + char *in = src; + char *out = dst; + + /* + * Check UUE block size + */ + if( (szsrc % 4) == 1 ) + { + log("Hydra: not enough characters in UUE block"); + return NULL; + } + + /* + * Check destination buffer size to avoid overflows + */ + if( ((szsrc / 4) * 4 + (szsrc % 4)) > szdst ) + { + log("Hydra: buffer overflow in UU decoder"); + return NULL; + } + + /* + * UU decoder + */ + while( szsrc >= 4 ) + { + if( !HYDRA_ISUUE(in[0]) || !HYDRA_ISUUE(in[1]) + || !HYDRA_ISUUE(in[2]) || !HYDRA_ISUUE(in[3]) ) + { + log("Hydra: character out of range in UUE block"); + return NULL; + } + + *out++ = (unsigned char)((HYDRA_UUDEC(in[0]) << 2) + | (HYDRA_UUDEC(in[1]) >> 4)); + *out++ = (unsigned char)((HYDRA_UUDEC(in[1]) << 4) + | (HYDRA_UUDEC(in[2]) >> 2)); + *out++ = (unsigned char)((HYDRA_UUDEC(in[2]) << 6) + | (HYDRA_UUDEC(in[3]) )); + + in += 4; + szsrc -= 4; + } + + if( szsrc >= 2 ) + { + if( !HYDRA_ISUUE(in[0]) || !HYDRA_ISUUE(in[1]) ) + { + log("Hydra: character out of range in UUE block"); + return NULL; + } + *out++ = (unsigned char)((HYDRA_UUDEC(in[0]) << 2) + | (HYDRA_UUDEC(in[1]) >> 4)); + + if( szsrc == 3 ) + { + if( !HYDRA_ISUUE(in[2]) ) + { + log("Hydra: character out of range in UUE block"); + return NULL; + } + *out++ = (unsigned char)((HYDRA_UUDEC(in[1]) << 4) + | (HYDRA_UUDEC(in[2]) >> 2)); + } + } + + return out; +} + +static int hydra_recv(s_hydrainfo *hi) +{ + int n, c; + char *p; + bool goodcrc = FALSE; + int pkttype; + + while( (c = GETCHAR(0)) >= 0 ) + { + if( hi->rxoptions & HOPT_HIGHBIT ) + c &= 0x7f; + + n = c; + if( hi->rxoptions & HOPT_HIGHCTL ) + n &= 0x7f; + + if( (n != HYDRA_DLE) + && (((hi->rxoptions & HOPT_XONXOFF) && ((n == XON) || (n == XOFF))) + || ((hi->rxoptions & HOPT_CTLCHRS) && ((n < 32 ) || (n == 127 )))) ) + { + DEB((D_PROT, "hydra_recv: received character 0x%02x discarded", n)); + continue; + } + + if( c == HYDRA_DLE ) + { + if( ++hi->idlecnt >= 5 ) + { + log("Hydra: got 5 DLE characters (abort)"); + return HPKT_EXIT; + } + } + else if( hi->idlecnt ) + { + hi->idlecnt = 0; + + switch(c) { + case HCHR_PKTEND: + if( hi->iencrcv ) + { + size_t encsize = hi->iencptr - hi->iencbuf; + + switch(hi->iencfmt) { + case HCHR_BINPKT: + p = hydra_getbinblock(hi->ibuf, HYDRA_MAXDATALEN, hi->iencbuf, encsize); + break; + case HCHR_HEXPKT: + p = hydra_gethexblock(hi->ibuf, HYDRA_MAXDATALEN, hi->iencbuf, encsize); + break; + case HCHR_ASCPKT: + p = hydra_getascblock(hi->ibuf, HYDRA_MAXDATALEN, hi->iencbuf, encsize); + break; + case HCHR_UUEPKT: + p = hydra_getuueblock(hi->ibuf, HYDRA_MAXDATALEN, hi->iencbuf, encsize); + break; + default: + ASSERT(0); + } + + hi->iencrcv = FALSE; + hi->iencptr = hi->iencbuf; + + if( !p ) + { + log("Hydra: error decoding packet format %d", + hi->iencfmt); + return HPKT_NONE; + } + + /* + * Calculate decoded packet size + */ + hi->isize = p - hi->ibuf; + + if( (hi->iencfmt != HCHR_HEXPKT) && (hi->rxoptions & HOPT_CRC32) ) + { + goodcrc = CRC32TEST(getcrc32ccitt(hi->ibuf, hi->isize)); + hi->isize -= 4; /* remove CRC-32 */ + } + else + { + goodcrc = CRC16TEST(getcrc16ccitt(hi->ibuf, hi->isize)); + hi->isize -= 2; /* remove CRC-16 */ + } + + --hi->isize; /* remove packet type */ + + if( hi->isize >= 0 ) + { + pkttype = hi->ibuf[hi->isize]; + +#ifdef DEBUG + hydra_pktdebug(FALSE, hi, hi->ibuf, pkttype, hi->iencfmt, + (hi->iencfmt != HCHR_HEXPKT && (hi->rxoptions & HOPT_CRC32)), + hi->isize); +#endif + + if( !goodcrc ) + log("Hydra: CRC test failed"); + else if( pkttype < HPKT_MIN || pkttype > HPKT_MAX ) + log("Hydra: packet type %d out of range", + pkttype); + else + return pkttype; + } else + log("Hydra: got invalid packet (ignored)"); + } else + log("Hydra: got unexpected packet end"); + + DEB((D_PROT, "hydra_recv: broken packet")); + + /* Return junk error */ + return HPKT_JUNK; + + case HCHR_BINPKT: + case HCHR_HEXPKT: + case HCHR_ASCPKT: + case HCHR_UUEPKT: + if( hi->iencrcv ) + log("Hydra: packet was not received completly"); + + hi->iencrcv = TRUE; + hi->iencptr = hi->iencbuf; + hi->iencfmt = c; + + DEB((D_PROT, "hydra_recv: start receiving '%s' (%d) packet", + HYDRA_CHRNAME(hi->iencfmt), hi->iencfmt)); + break; + + default: + if( hi->iencrcv ) + { + if( hi->iencptr - hi->iencbuf < HYDRA_BUFLEN ) + *hi->iencptr++ = c ^ 0x40; + else + { + log("Hydra: packet too long"); + hi->iencrcv = FALSE; + hi->iencptr = hi->iencbuf; + } + } +#ifdef DEBUG + else + DEB((D_PROT, "hydra_recv: ignore 0x%02x (escaped)", c ^ 0x40)); +#endif + } + } + else if( hi->iencrcv ) + { + if( hi->iencptr - hi->iencbuf < HYDRA_BUFLEN ) + *hi->iencptr++ = c; + else + { + log("Hydra: packet too long"); + hi->iencrcv = FALSE; + hi->iencptr = hi->iencbuf; + } + } +#ifdef DEBUG + else + DEB((D_PROT, "hydra_recv: ignore 0x%02x", c)); +#endif + } + + return (c == TTY_TIMEOUT) ? HPKT_NONE : HPKT_EXIT; +} + +/* + * Parse received INIT packet. Return -1 value if got unparsable/invalid + * INIT packet. Probably we should abort transfer in case of such error. + */ +static int hydra_parse_init(s_hydrainfo *hi, char *pkt, size_t pktlen) +{ + char *appinf; /* Application info */ + char *canopt; /* Supported options */ + char *desopt; /* Desired options */ + char *window; /* Tx/Rx window sizes */ + char *prefix; /* Prefix string */ + char *endptr = pkt + pktlen; + time_t revtime; + + if( pktlen > 8 && pkt[pktlen-1] == '\0' ) + { + /* + * Get other's Hydra revision time stamp + */ + sscanf(pkt, "%08lx", &revtime); + + /* + * Get other's application info + */ + appinf = pkt + 8; + + /* + * Get other's supported options, desired options, + * rx/tx windows sizes and packet prefix string + */ + canopt = (appinf && appinf < endptr) ? appinf + strlen(appinf) + 1 : NULL; + desopt = (canopt && canopt < endptr) ? canopt + strlen(canopt) + 1 : NULL; + window = (desopt && desopt < endptr) ? desopt + strlen(desopt) + 1 : NULL; + prefix = (window && window < endptr) ? window + strlen(window) + 1 : NULL; + + if( appinf && canopt && desopt && window && prefix ) + { + char buf[256]; + long txwindow = 0L; + long rxwindow = 0L; + + DEB((D_PROT, "hydra: revtime = \"%s\"", time_string_long(buf, sizeof(buf), revtime))); + DEB((D_PROT, "hydra: appinf = \"%s\"", appinf)); + DEB((D_PROT, "hydra: canopt = \"%s\"", canopt)); + DEB((D_PROT, "hydra: desopt = \"%s\"", desopt)); + DEB((D_PROT, "hydra: window = \"%s\"", window)); + DEB((D_PROT, "hydra: prefix = \"%s\"", prefix)); + + hi->rxoptions = hi->options; + hi->rxoptions |= hydra_getflags(desopt); + hi->rxoptions &= hydra_getflags(canopt); + hi->rxoptions &= HYDRA_CANOPT; + hi->txoptions = hi->rxoptions; + + if( hi->rxoptions < (hi->options & HYDRA_NECOPT) ) + { + log("Hydra is incompartible on this link"); + return -1; + } + + sscanf(window, "%08lx%08lx", &txwindow, &rxwindow); + + if( txwindow < 0 ) txwindow = 0L; + if( rxwindow < 0 ) rxwindow = 0L; + + /* + * Log other's hydra information only at 1st batch + */ + if( !hi->batchesdone ) + { + if( hi->rxoptions ) + { + hydra_putflags(buf, hi->rxoptions, sizeof(buf)); + log("Hydra init \"%s\", \"%s\"", + string_printable(appinf), buf); + } + else + { + log("Hydra init \"%s\"", + string_printable(appinf)); + } + hi->batchesdone = TRUE; + } + + if( (hi->txwindow != txwindow) + || (hi->rxwindow != rxwindow) ) + { + log("Hydra Tx/Rx windows = %ld/%ld bytes", + txwindow, rxwindow); + hi->txwindow = txwindow; + hi->rxwindow = rxwindow; + } + + return 0; + } + } + + log("Hydra got invalid INIT packet"); + + return -1; +} + +static void hydra_align_block_size(int *block_size) +{ + int n = *block_size; + + if( n <= 64 ) + n = 64; + else if( n <= 128 ) + n = 128; + else if( n <= 256 ) + n = 256; + else if( n <= 512 ) + n = 512; + else if( n <= 1024 ) + n = 1024; + else + n = 2048; + + *block_size = n; +} + +static void hydra_init(s_hydrainfo *hi) +{ + memset(hi, '\0', sizeof(s_hydrainfo)); + + /* + * RPOS ID sequence starting value + */ + hi->recv_rpos_id = 100; + hi->send_rpos_id = -1; + + /* + * Set rx/tx block sizes + */ + hi->send_block_size = 1024; + hi->recv_block_size = 1024; + + /* + * Set timeout values + */ + hi->timeout_send = 30; + hi->timeout_recv = 30; + hi->timeout_dead = 120; + + /* + * Set start up link options + */ + hi->options = HYDRA_DEFOPT & HYDRA_CANOPT; + hi->txoptions = HYDRA_TXIOPT; + hi->rxoptions = HYDRA_RXIOPT; + + hi->lastchar = -1; + hi->oencbuf = xmalloc(HYDRA_BUFLEN); + hi->oencptr = hi->oencbuf; + hi->iencbuf = xmalloc(HYDRA_BUFLEN); + hi->iencptr = hi->iencbuf; + hi->obuf = xmalloc(HYDRA_MAXDATALEN); + hi->ibuf = xmalloc(HYDRA_MAXDATALEN); +} + +static void hydra_deinit(s_hydrainfo *hi) +{ + if( hi->iencbuf ) free(hi->iencbuf); + if( hi->oencbuf ) free(hi->oencbuf); + if( hi->ibuf ) free(hi->ibuf); + if( hi->obuf ) free(hi->obuf); + + memset(hi, '\0', sizeof(s_hydrainfo)); +} + +int hydra_batch(s_hydrainfo *hi, s_protinfo *pi) +{ + int rc = PRC_NOERROR; + int n; + char *p; + bool send_EOB = FALSE; + int send_rc = 0; + int recv_rc = 0; + bool send_ready = FALSE; + bool recv_ready = FALSE; + enum hydra_txstate txstate = HTX_START; + enum hydra_rxstate rxstate = HRX_INIT; + int txtries = 0; + int rxtries = 0; + long txlastack = 0L; + long rxlastack = 0L; + time_t idletimer = 0; + time_t sendtimer = 0; + time_t recvtimer = 0; + time_t deadtimer = 0; +#ifdef DEBUG + int prev_txstate = -1; + int prev_rxstate = -1; +#endif + long last_datapos = -1; /* The last received DATA block offset */ + + timer_set(&deadtimer, hi->timeout_dead); + + while( txstate != HTX_DONE || rxstate != HRX_DONE ) + { +#ifdef DEBUG + if( txstate != prev_txstate || rxstate != prev_rxstate ) + { + prev_txstate = txstate; + prev_rxstate = rxstate; + DEB((D_PROT, "hydra: txstate = '%s' (%d), rxstate = '%s' (%d)", + HYDRA_TXSTATE(txstate), txstate, + HYDRA_RXSTATE(rxstate), rxstate)); + } +#endif + + if( timer_running(deadtimer) && timer_expired(deadtimer) ) + { + log("remote dead (timer expired)"); + gotoexit(PRC_ERROR); + } + + if( timer_running(sendtimer) && timer_expired(sendtimer) ) + { + sendtimer = 0; + switch(txstate) { + case HTX_SWAIT: txstate = HTX_START; break; + case HTX_INITACK: txstate = HTX_INIT; break; + case HTX_FINFOACK: txstate = HTX_FINFO; break; + case HTX_DATAACK: txstate = HTX_DATA; break; /* Incorrect! */ + case HTX_EOFACK: txstate = HTX_EOF; break; + case HTX_ENDACK: txstate = HTX_END; break; + default: + log("sendtimer expired, but txstate = %s #%d", + HYDRA_TXSTATE(txstate), txstate); + } + DEB((D_PROT, "hydra: send timer expired, new txstate = '%s' #%d", + HYDRA_TXSTATE(txstate), txstate)); + } + + if( timer_running(recvtimer) && timer_expired(recvtimer) ) + { + recvtimer = 0; + switch(rxstate) { + case HRX_RPosAck: + /* Decrease data block size */ + hi->recv_block_size >>= 1; + hydra_align_block_size(&hi->recv_block_size); + + /* Send RPOS packet again */ + rxstate = HRX_RPOS; + break; + + case HRX_SkipAck: rxstate = HRX_Skip; break; + case HRX_DATA: rxstate = HRX_RPOS; break; + default: + log("recvtimer expired, but rxstate = %s #%d", + HYDRA_RXSTATE(rxstate), rxstate); + } + DEB((D_PROT, "hydra: recv timer expired, new rxstate = '%s' #%d", + HYDRA_RXSTATE(rxstate), rxstate)); + } + + switch(txstate) { + case HTX_START: + if( ++txtries < 10 ) + { + timer_set(&sendtimer, hi->timeout_send); + PUTSTR("hydra\r"); + hydra_queuepkt(hi, NULL, 0, HPKT_START); + txstate = HTX_SWAIT; + } + else + { + log("Hydra unable to initiate session"); + gotoexit(PRC_ERROR); + } + break; + + case HTX_INIT: + if( ++txtries < 10 ) + { + timer_set(&sendtimer, hi->timeout_send); + + p = hi->obuf; + + /* Application info */ + p += sprintf(p, "%08lx%s,%s", (long)0L, BF_NAME, BF_VERSION) + 1; + + /* What we can */ + p = hydra_putflags(p, HYDRA_CANOPT, 256) + 1; + + /* What we want */ + p = hydra_putflags(p, HYDRA_DEFOPT, 256) + 1; + + /* Tx/Rx window sizes */ + p += sprintf(p, "%08lx%08lx", (long)0L, (long)0L) + 1; + + /* Pkt prefix string we want */ + *p++ = '\0'; + + hydra_queuepkt(hi, hi->obuf, p - hi->obuf, HPKT_INIT); + txstate = HTX_INITACK; + } + else + { + log("Hydra too many tries sending INIT packet"); + gotoexit(PRC_ERROR); + } + break; + + case HTX_RINIT: + if( rxstate != HRX_INIT ) + txstate = HTX_NextFile; + break; + + case HTX_NextFile: + if( pi->send && pi->send->fp ) + p_tx_fclose(pi); + + send_EOB = p_tx_fopen(pi) ? TRUE : FALSE; + + txtries = 0; + txstate = HTX_FINFO; + + /* FALL THROUGH */ + + case HTX_FINFO: + if( ++txtries < 10 ) + { + timer_set(&sendtimer, hi->timeout_send); + + if( send_EOB == FALSE ) + { + char dosname[13]; + + n = sprintf(hi->obuf, "%08lx%08lx%08lx%08lx%08lx", + (long)pi->send->mod_time, + (long)pi->send->bytes_total, + (long)0L, (long)0L, (long)0L); + + file_get_dos_name(dosname, pi->send->net_name); + strnxcpy(hi->obuf + n, dosname, BFORCE_MAX_NAME); + n += strlen(hi->obuf + n) + 1; + + if( strcmp(dosname, pi->send->net_name) ) + { + strnxcpy(hi->obuf + n, pi->send->net_name, BFORCE_MAX_NAME); + n += strlen(hi->obuf + n) + 1; + } + } + else /* Send 'EOB' */ + { + n = 1; + hi->obuf[0] = '\0'; + } + + hydra_queuepkt(hi, hi->obuf, n, HPKT_FINFO); + txstate = HTX_FINFOACK; + } + else + { + log("Hydra too many tries sending FINFO packet"); + gotoexit(PRC_ERROR); + } + break; + + case HTX_DATA: + if( pi->send->eofseen ) + { + txtries = 0; + txstate = HTX_EOF; + } + else if( hi->oencpos == 0 && hi->n_pkts == 0 ) + { + sendtimer = 0; + + n = p_tx_readfile(hi->obuf+4, hi->send_block_size, pi); + if( n > 0 ) + { + timer_set(&deadtimer, hi->timeout_dead); + + hydra_putlong(hi->obuf, (long)pi->send->bytes_sent); + pi->send->bytes_sent += n; + + p = hydra_putpkt(hi, hi->oencbuf, hi->obuf, n+4, HPKT_DATA); + hi->oencpos = p - hi->oencbuf; + + /* Increase number of good blocks */ + ++hi->send_good_blocks; + + /* Is it a good time for raising block size? */ + if( hi->send_block_size < 2048 ) + { + if( (hi->send_good_blocks * hi->send_block_size) >= 4096 ) + { + hi->send_good_blocks = 0; + hi->send_block_size <<= 1; + hydra_align_block_size(&hi->send_block_size); + DEB((D_PROT, "hydra: Tx now use %ld bytes blocks", + (long)hi->send_block_size)); + } + } + + if( (hi->txwindow > 0) + && (pi->send->bytes_sent >= txlastack + hi->txwindow) ) + { + /* + * Tx window reached its maximal size, + * continue sending only after receiving + * of DATAACK packet with correct offset + */ + if( txtries > 0 ) + timer_set(&sendtimer, hi->timeout_send/2); + else + timer_set(&sendtimer, hi->timeout_send); + + txstate = HTX_DATAACK; + } + else if( pi->send->eofseen ) + { + txtries = 0; + txstate = HTX_EOF; + } + } + else + { + txtries = 0; + txstate = HTX_EOF; + } + } + break; + + case HTX_EOF: + if( ++txtries < 10 ) + { + timer_set(&sendtimer, hi->timeout_send); + + if( pi->send ) + { + if( pi->send->status == FSTAT_SKIPPED ) + hydra_putlong(hi->obuf, (long)-1L); + else if( pi->send->status == FSTAT_REFUSED ) + hydra_putlong(hi->obuf, (long)-2L); + else if( pi->send->eofseen ) + hydra_putlong(hi->obuf, (long)pi->send->bytes_sent); + else + hydra_putlong(hi->obuf, (long)-2L); + } + else + hydra_putlong(hi->obuf, (long)-2L); + + hydra_queuepkt(hi, hi->obuf, 4, HPKT_EOF); + txstate = HTX_EOFACK; + } + else + { + log("Hydra too many tries sending EOF packet"); + gotoexit(PRC_ERROR); + } + break; + + case HTX_REND: + if( rxstate == HRX_DONE ) + { + txtries = 0; + txstate = HTX_END; + } + else if( !timer_running(idletimer) || timer_expired(idletimer) ) + { + timer_set(&idletimer, 20); + hydra_queuepkt(hi, NULL, 0, HPKT_IDLE); + } + break; + + case HTX_END: + if( ++txtries < 10 ) + { + timer_set(&sendtimer, hi->timeout_send); + hydra_queuepkt(hi, NULL, 0, HPKT_END); + txstate = HTX_ENDACK; + } + else + { + log("Hydra too many tries sending END packet"); + gotoexit(PRC_ERROR); + } + break; + + default: + /* Do nothing, but avoid warning message */ + break; + } + + switch(rxstate) { + case HRX_RPOS: + case HRX_Skip: + if( ++rxtries < 10 ) + { + long pos; + + timer_set(&recvtimer, hi->timeout_recv); + + if( rxstate == HRX_Skip ) + pos = (pi->recv->status == FSTAT_SKIPPED) ? -1L : -2L; + else + pos = pi->recv->bytes_received; + + hydra_putlong(hi->obuf, pos); + hydra_putword(hi->obuf + 4, hi->recv_block_size); + hydra_putlong(hi->obuf + 6, hi->recv_rpos_id); + hydra_queuepkt(hi, hi->obuf, 10, HPKT_RPOS); + + rxstate = (rxstate == HRX_Skip) ? HRX_SkipAck : HRX_RPosAck; + } + else + { + log("Hydra too many tries sending RPOS packet"); + gotoexit(PRC_ERROR); + } + break; + + default: + /* Do nothing, but avoid warning message */ + break; + } + +#ifdef DEBUG + if( txstate != prev_txstate || rxstate != prev_rxstate ) + { + prev_txstate = txstate; + prev_rxstate = rxstate; + DEB((D_PROT, "hydra: txstate = '%s' (%d), rxstate = '%s' (%d)", + HYDRA_TXSTATE(txstate), txstate, + HYDRA_RXSTATE(rxstate), rxstate)); + } +#endif + + /* + * Check current CPS, session time limits, etc. + */ + if( (rc = p_info(pi, 1)) ) gotoexit(rc); + + /* + * Send/receive as much data as possible, but without delays + */ + send_ready = recv_ready = FALSE; + + if( hi->oencpos > 0 || hi->n_pkts ) + n = tty_xselect(&recv_ready, &send_ready, 10); + else + n = tty_xselect(&recv_ready, NULL, 10); + + if( n < 0 && n != TTY_TIMEOUT ) + gotoexit(PRC_ERROR); + + recv_rc = HPKT_NONE; + send_rc = 0; + + if( recv_ready && (recv_rc = hydra_recv(hi)) == HPKT_EXIT ) + gotoexit(PRC_ERROR); + if( send_ready && (send_rc = hydra_send(hi)) < 0 ) + gotoexit(PRC_ERROR); + + switch(recv_rc) { + case HPKT_NONE: + break; + + case HPKT_JUNK: + if( rxstate == HRX_DATA ) + { + /* Increase RPOS packet ID number */ + hi->recv_rpos_id++; + + /* Decrease data block size */ + hi->recv_block_size >>= 1; + hydra_align_block_size(&hi->recv_block_size); + + rxtries = 0; + rxstate = HRX_RPOS; + } + break; + + case HPKT_START: + if( txstate == HTX_START || txstate == HTX_SWAIT ) + { + txtries = 0; + txstate = HTX_INIT; + } + break; + + case HPKT_INIT: + if( rxstate == HRX_INIT ) + { + if( hydra_parse_init(hi, hi->ibuf, hi->isize) ) + { + gotoexit(PRC_ERROR); + } + rxtries = 0; + rxstate = HRX_FINFO; + } + hydra_queuepkt(hi, NULL, 0, HPKT_INITACK); + break; + + case HPKT_INITACK: + if( txstate == HTX_INIT || txstate == HTX_INITACK ) + { + txtries = 0; + txstate = HTX_RINIT; + } + break; + + case HPKT_FINFO: + if( rxstate == HRX_FINFO ) + { + /* Check for EOB FINFO packet */ + if( hi->ibuf[0] == '\0' ) + { + hydra_putlong(hi->obuf, 0L); + hydra_queuepkt(hi, hi->obuf, 4, HPKT_FINFOACK); + rxstate = HRX_DONE; + } + else if( hi->isize > 41 && hi->ibuf[hi->isize-1] == '\0' ) + { + time_t modtime; + size_t filesize; + char *filename; + char *p; + + /* Get file modification time and size */ + sscanf(hi->ibuf, "%08lx%08x%*08x%*08x%*08x", + &modtime, &filesize); + + /* Convert local time -> UTC */ + modtime = localtogmt(modtime); + + /* Select short file name */ + filename = p = hi->ibuf + 40; + while( *p && p < (hi->ibuf + hi->isize) ) + ++p; + + if( p == filename ) + { + /* Got FINFO without file name */ + filename = "bad_name"; + } + else if( *p ) + { + /* Got not null-terminated file name */ + *(++p) = '\0'; + } + else + { + /* Try long file name */ + char *long_filename = ++p; + + while( *p && p < (hi->ibuf + hi->isize) ) + ++p; + + /* Accept only null-terminated long file names */ + if( *p == '\0' && p > long_filename ) + filename = long_filename; + } + + switch( p_rx_fopen(pi, filename, filesize, modtime, 0) ) { + case 0: /* No errors */ + rxlastack = (long)pi->recv->bytes_skipped; + last_datapos = -1; + hydra_putlong(hi->obuf, (long)pi->recv->bytes_skipped); + timer_set(&recvtimer, hi->timeout_recv); + rxstate = HRX_DATA; + break; + + case 1: /* SKIP (non-destructive) */ + hydra_putlong(hi->obuf, -2L); + break; + + case 2: /* SKIP (destructive) */ + hydra_putlong(hi->obuf, -1L); + break; + + default: + ASSERT(0); + } + hydra_queuepkt(hi, hi->obuf, 4, HPKT_FINFOACK); + } + else + log("Hydra: got invalid FINFO packet (ignored)"); + } + else if( rxstate == HRX_DONE ) + { + hydra_putlong(hi->obuf, -2); + hydra_queuepkt(hi, hi->obuf, 4, HPKT_FINFOACK); + } + else + log("Hydra: unexpected FINFO packet (ignored)"); + break; + + case HPKT_FINFOACK: + if( txstate == HTX_FINFO || txstate == HTX_FINFOACK ) + { + long offs = 0L; + + if( send_EOB == TRUE ) + { + timer_set(&idletimer, 20); + sendtimer = 0; + txtries = 0; + txstate = HTX_REND; + } + else if( hi->isize < 4 ) + { + log("Hydra: got invalid FINFOACK packet (ignored)"); + } + else if( (offs = hydra_getlong(hi->ibuf)) == 0 ) + { + txlastack = 0; + txtries = 0; + txstate = HTX_DATA; + } + else if( offs > 0 ) + { + if( fseek(pi->send->fp, offs, SEEK_SET) == 0 ) + { + txlastack = offs; + pi->send->bytes_skipped = pi->send->bytes_sent = offs; + log("send file from offset %ld bytes", offs); + txtries = 0; + txstate = HTX_DATA; + } + else + { + logerr("can't send file from requested offset %ld", offs); + p_tx_fclose(pi); + txstate = HTX_NextFile; + } + } + else if( offs == -1 ) + { + pi->send->status = FSTAT_SKIPPED; + log("remote allready has file"); + p_tx_fclose(pi); + txstate = HTX_NextFile; + } + else /* Send file later */ + { + pi->send->status = FSTAT_REFUSED; + log("remote refused file"); + p_tx_fclose(pi); + txstate = HTX_NextFile; + } + } + break; + + case HPKT_DATA: + if( rxstate == HRX_DATA || rxstate == HRX_RPosAck ) + { + if( hi->isize < 4 ) + { + log("Hydra: got invalid DATA packet (ignored)"); + } + else if( hydra_getlong(hi->ibuf) != pi->recv->bytes_received ) + { + long pos = hydra_getlong(hi->ibuf); + + if( rxstate == HRX_RPosAck ) + { + if( pos < last_datapos ) + rxstate = HRX_RPOS; + } + else /* rxstate == HRX_DATA */ + { + /* Increase RPOS packet ID number */ + hi->recv_rpos_id++; + + /* Decrease data block size */ + hi->recv_block_size >>= 1; + hydra_align_block_size(&hi->recv_block_size); + + rxtries = 0; + rxstate = HRX_RPOS; + } + last_datapos = pos; + } + else /* Write to the file */ + { + hi->recv_block_size = hi->isize-4; + last_datapos = hydra_getlong(hi->ibuf); + + timer_set(&deadtimer, hi->timeout_dead); + timer_set(&recvtimer, hi->timeout_recv); + + if( rxstate == HRX_RPosAck ) + rxstate = HRX_DATA; + + switch(p_rx_writefile(hi->ibuf+4, hi->isize-4, pi)) { + case 0: + if( hi->rxwindow > 0 ) + { + /* + * It is not the best idea to + * acknowledge every data packet, + * but is so easy to implement :) + */ + rxlastack = (long)pi->recv->bytes_received; + hydra_putlong(hi->obuf, (long)pi->recv->bytes_received); + hydra_queuepkt(hi, hi->obuf, 4, HPKT_DATAACK); + } + + pi->recv->bytes_received += hi->isize-4; + break; + + case -1: /* SKIP (non-destructive) */ + pi->recv->status = FSTAT_REFUSED; + hi->recv_rpos_id++; + rxtries = 0; + rxstate = HRX_Skip; + break; + + case -2: /* SKIP (destructive) */ + pi->recv->status = FSTAT_SKIPPED; + hi->recv_rpos_id++; + rxtries = 0; + rxstate = HRX_Skip; + break; + + default: + ASSERT(0); + } + } + } + break; + + case HPKT_DATAACK: + if( txstate == HTX_DATA || txstate == HTX_DATAACK ) + { + long ackpos = hydra_getlong(hi->ibuf); + + if( ackpos >= pi->send->bytes_sent ) + log("Hydra got DATAACK from feature"); + else if( ackpos < txlastack ) + log("Hydra got DATAACK from past"); + else + { + txlastack = ackpos; + + if( (txstate == HTX_DATAACK) + && (pi->send->bytes_sent < txlastack + hi->txwindow) ) + { + txtries = 0; + txstate = HTX_DATA; + } + } + } + break; + + case HPKT_RPOS: + if( txstate == HTX_DATA || txstate == HTX_DATAACK + || txstate == HTX_XWAIT + || txstate == HTX_EOF || txstate == HTX_EOFACK ) + { + if( hi->isize < 10 ) + { + log("Hydra: got invalid RPOS packet (ignored)"); + } + else + { + long offset = hydra_getlong(hi->ibuf); + int blocksize = hydra_getword(hi->ibuf + 4); + long packetId = hydra_getlong(hi->ibuf + 6); + + /* Check requested block size */ + if( blocksize > 0 ) + hydra_align_block_size(&blocksize); + + if( packetId > 0 && packetId == hi->send_rpos_id ) + { + log("Hydra Tx got duplicated RPOS packet (ignore)"); + } + else if( offset >= 0 ) + { + /* Reset EOF flag! */ + pi->send->eofseen = FALSE; + + /* Store ID of the processed RPOS */ + hi->send_rpos_id = packetId; + + if( fseek(pi->send->fp, offset, SEEK_SET) == 0 + && ftell(pi->send->fp) == offset ) + { + txlastack = offset; /* Is it OK? */ + + log("Hydra Tx resend from %ld", + (long)offset); + + pi->send->bytes_sent = offset; + + if( blocksize && blocksize != hi->send_block_size ) + { + log("Hydra Tx use %ld bytes blocks", + (long)blocksize); + hi->send_block_size = blocksize; + hi->send_good_blocks = 0; + } + + if( txstate != HTX_XWAIT ) + txstate = HTX_DATA; + } + else + { + log("Hydra Tx can't resend from %ld", (long)offset); + + pi->send->status = FSTAT_REFUSED; + txtries = 0; + txstate = HTX_EOF; + } + } + else if( offset == -1 ) + { + log("Hydra Tx skipping file"); + + /* Store ID of the processed RPOS */ + hi->send_rpos_id = packetId; + + pi->send->status = FSTAT_SKIPPED; + txtries = 0; + txstate = HTX_EOF; + } + else + { + log("Hydra Tx refusing file"); + + /* Store ID of the processed RPOS */ + hi->send_rpos_id = packetId; + + pi->send->status = FSTAT_REFUSED; + txtries = 0; + txstate = HTX_EOF; + } + } + } + break; + + case HPKT_EOF: + if( rxstate == HRX_DATA ) + { + if( hi->isize < 4 ) + { + log("Hydra: got invalid EOF packet (ignored)"); + } + else if( hydra_getlong(hi->ibuf) != pi->recv->bytes_received ) + { + last_datapos = hydra_getlong(hi->ibuf); + + /* Increase RPOS packet ID number */ + hi->recv_rpos_id++; + + /* Decrease data block size */ + hi->recv_block_size >>= 1; + hydra_align_block_size(&hi->recv_block_size); + + rxtries = 0; + rxstate = HRX_RPOS; + } + else + { + pi->recv->status = FSTAT_SUCCESS; + + if( p_rx_fclose(pi) == 0 ) + { + hydra_queuepkt(hi, NULL, 0, HPKT_EOFACK); + rxtries = 0; + rxstate = HRX_FINFO; + } + else /* Error closing file */ + { + pi->recv->status = FSTAT_REFUSED; + rxtries = 0; + rxstate = HRX_Skip; + } + } + } + else if( rxstate == HRX_Skip || rxstate == HRX_SkipAck ) + { + if( hi->isize < 4 ) + { + log("Hydra: got invalid EOF packet (ignored)"); + } + else if( hydra_getlong(hi->ibuf) >= 0 ) + { + /* + * Possible they didn't seen our + * RPOS(-2) packet. If we send EOFACK + * packet now, file will be lost! :( + * There is such "bug" in 'Argus'? + * So we will Skip it again, again.. + */ + rxstate = HRX_Skip; + } + else + { + hydra_queuepkt(hi, NULL, 0, HPKT_EOFACK); + (void)p_rx_fclose(pi); + recvtimer = 0; + rxtries = 0; + rxstate = HRX_FINFO; + } + } + else if( hi->isize == 4 && hydra_getlong(hi->ibuf) == -2 ) + { + /* + * We will ack. all received EOF packets + * (even unexpected) with (-2) offset, + * it is not harmfull. + */ + hydra_queuepkt(hi, NULL, 0, HPKT_EOFACK); + } + else + { + log("Hydra got unexpected EOF packet"); + } + break; + + case HPKT_EOFACK: + if( txstate == HTX_EOF || txstate == HTX_EOFACK ) + { + if( pi->send ) + { + if( pi->send->eofseen ) + pi->send->status = FSTAT_SUCCESS; + p_tx_fclose(pi); + txstate = HTX_NextFile; + } + else + { + txtries = 0; + txstate = HTX_END; + } + } + break; + + case HPKT_END: + if( txstate == HTX_END || txstate == HTX_ENDACK ) + { + hydra_queuepkt(hi, NULL, 0, HPKT_END); + hydra_queuepkt(hi, NULL, 0, HPKT_END); + hydra_queuepkt(hi, NULL, 0, HPKT_END); + txtries = 0; + txstate = HTX_DONE; + } + break; + + case HPKT_IDLE: + timer_set(&recvtimer, hi->timeout_recv); + break; + + case HPKT_DEVDATA: + log("Hydra: ignore DEVDATA packet"); + break; + + case HPKT_DEVDACK: + log("Hydra: ignore DEVDACK packet"); + break; + + default: + log("Hydra: unhandled packet type #%d", recv_rc); + } + } + + /* + * Send queued packets and buffered data + */ + txtries = 0; + while( hi->oencpos > 0 || hi->n_pkts > 0 ) + { + if( ++txtries > 20 ) + gotoexit(PRC_ERROR); + + if( tty_select(NULL, &send_ready, 30) < 0 ) + gotoexit(PRC_ERROR); + + if( !send_ready || hydra_send(hi) ) + gotoexit(PRC_ERROR); + } + FLUSHOUT(); + +exit: + if( pi->send && pi->send->fp ) + p_tx_fclose(pi); + if( pi->recv && pi->recv->fp ) + p_rx_fclose(pi); + + return rc; +} + +int hydra(s_protinfo *pi, bool files_after_freqs) +{ + int rc; + s_hydrainfo hi; + + log("start Hydra send+receive%s", + files_after_freqs ? " (RH1 mode)" : ""); + + hydra_init(&hi); + + /* + * Send only file requests during first + * batch if EMSI 'RH1' flag specified + */ + if( files_after_freqs ) + pi->reqs_only = TRUE; + + rc = hydra_batch(&hi, pi); + + if( rc == PRC_NOERROR ) + { + if( files_after_freqs ) + pi->reqs_only = FALSE; + + rc = hydra_batch(&hi, pi); + } + + hydra_deinit(&hi); + + return rc; +} + diff --git a/source/bforce/prot_xmrecv.c b/source/bforce/prot_xmrecv.c new file mode 100644 index 0000000..de48c25 --- /dev/null +++ b/source/bforce/prot_xmrecv.c @@ -0,0 +1,15 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" diff --git a/source/bforce/prot_xmsend.c b/source/bforce/prot_xmsend.c new file mode 100644 index 0000000..de48c25 --- /dev/null +++ b/source/bforce/prot_xmsend.c @@ -0,0 +1,15 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" diff --git a/source/bforce/prot_yoohoo.c b/source/bforce/prot_yoohoo.c new file mode 100644 index 0000000..6c76c00 --- /dev/null +++ b/source/bforce/prot_yoohoo.c @@ -0,0 +1,591 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "session.h" +#include "prot_yoohoo.h" + +typedef enum { + YS_Init, + YS_SendHello, + YS_WaitResp, + YS_Done, + YS_Error +} YooHoo_SendState; + +typedef enum { + YR_Init, + YR_SendENQ, + YR_WaitHeader, + YR_TossJunk, + YR_RecvHello, + YR_SendNAK, + YR_SendACK, + YR_Done, + YR_Error +} YooHoo_RecvState; + +static char *yoohoo_putword(char *buf, int val) +{ + buf[0] = ( ((unsigned int) val) ) & 0xff; + buf[1] = ( ((unsigned int) val) >> 8 ) & 0xff; + + return buf + 2; +} + +static int yoohoo_getword(const char *buf) +{ + return ( (unsigned int) ((unsigned char) buf[0]) ) + | ( (unsigned int) ((unsigned char) buf[1]) << 8 ); +} + +/***************************************************************************** + * Make ``hello'' packet from the yoohoo sysinfo structure and put + * it to the buffer + * + * Arguments: + * buffer pointer to the destination buffer (must be at least + * 128 bytes) + * hello structure with the YooHoo system information + * + * Return value: + * None + */ +static void yoohoo_put_hello(char *buffer, s_yoohoo_sysinfo *hello) +{ + char *p, *q; + + ASSERT(buffer && hello); + + memset(buffer, '\0', YOOHOO_HELLOLEN); + + p = buffer; + p = yoohoo_putword(p, 0x6f); + p = yoohoo_putword(p, 0x01); /* Hello version */ + p = yoohoo_putword(p, hello->product_code); /* Product code */ + p = yoohoo_putword(p, hello->version_maj); /* Major version */ + p = yoohoo_putword(p, hello->version_min); /* Minor version */ + + strnxcpy(p, hello->system, 60); /* Node name */ + + /* + * Add domain after the end of 'Node name' + * TODO: check it for buffer overflows %-I + */ + if( hello->anum > 0 && hello->addrs[0].addr.domain + && *hello->addrs[0].addr.domain ) + { + char *q; + if( strlen(hello->system) + strlen(hello->addrs[0].addr.domain) > 57 ) + { + if( strlen(hello->addrs[0].addr.domain) < 60 ) + q = p + (60 - strlen(hello->addrs[0].addr.domain)); + else + q = p; + + *q++ = '\0'; + } + else + { + q = p + strlen(hello->system) + 1; + } + strnxcpy(q, hello->addrs[0].addr.domain, 60-(q-p)); + } + p += 60; + + strnxcpy(p, hello->sysop, 20); /* SysOp name */ + p += 20; + + if( hello->anum > 0 ) + { + p = yoohoo_putword(p, hello->addrs[0].addr.zone); + p = yoohoo_putword(p, hello->addrs[0].addr.net); + p = yoohoo_putword(p, hello->addrs[0].addr.node); + p = yoohoo_putword(p, hello->addrs[0].addr.point); + } + else + p += 8; + + strncpy(p, hello->passwd, 8); /* Session password */ + p += 8; + p += 8; /* Reserved 8 bytes */ + p = yoohoo_putword(p, hello->capabilities); /* Capabilities */ + p += 12; /* Reserved 12 bytes */ + +#ifdef DEBUG + DEB((D_HSHAKE, "yoohoo_put_hello: HELLO dump: \"%s\"", + q = string_printable_buffer(buffer, 128))); + if( q ) free(q); +#endif + + ASSERT((p - buffer) == YOOHOO_HELLOLEN); +} + +/***************************************************************************** + * Extract session information from the ``hello'' packet + * + * Arguments: + * hello pointer to the destination structure with the session + * information + * buffer source buffer with ``hello'' packet + * + * Return value: + * None + */ +static int yoohoo_get_hello(s_yoohoo_sysinfo *hello, const char *buffer) +{ + s_faddr addr; + + ASSERT(buffer && hello); + +#ifdef DEBUG + { + char *q = string_printable_buffer(buffer, YOOHOO_HELLOLEN); + DEB((D_HSHAKE, "yoohoo_get_hello: HELLO dump: \"%s\"", q)); + if( q ) free(q); + } +#endif + + memset(hello, '\0', sizeof(s_yoohoo_sysinfo)); + + if( yoohoo_getword(buffer+2) != 0x01 ) + log("YooHoo hello version is %d!", yoohoo_getword(buffer+2)); + + hello->product_code = yoohoo_getword(buffer+4); + hello->version_maj = yoohoo_getword(buffer+6); + hello->version_min = yoohoo_getword(buffer+8); + strnxcpy(hello->system, buffer+10, MIN(sizeof(hello->system),60+1)); + strnxcpy(hello->sysop, buffer+70, MIN(sizeof(hello->sysop),20+1)); + + /* + * Extract address + */ + memset(&addr, '\0', sizeof(s_faddr)); + addr.zone = yoohoo_getword(buffer+90); + addr.net = yoohoo_getword(buffer+92); + addr.node = yoohoo_getword(buffer+94); + addr.point = yoohoo_getword(buffer+96); + session_addrs_add(&hello->addrs, &hello->anum, addr); + + strnxcpy(hello->passwd, buffer+98, MIN(sizeof(hello->passwd),8+1)); + /* Reserved 8 bytes */ + hello->capabilities = yoohoo_getword(buffer+114); + /* Reserved 12 bytes */ + + return 0; +} + +int yoohoo_send_hello(s_yoohoo_sysinfo *local_data) +{ + char hello_buffer[YOOHOO_HELLOLEN]; + unsigned short hello_crc = 0; + YooHoo_SendState state = YS_Init; + time_t wait_timer; + int tries = 0; + int rc; + + ASSERT(local_data); + + while(1) + { + switch(state) { + case YS_Init: + tries = 0; + yoohoo_put_hello(hello_buffer, local_data); + hello_crc = getcrc16xmodem(hello_buffer, YOOHOO_HELLOLEN); + state = YS_SendHello; + break; + + case YS_SendHello: + if( ++tries > 10 ) + { + log("too many tries sending hello"); + state = YS_Error; + break; + } + else if( tries > 1 ) + log("yoohoo hello send - retry %d", tries); + + if( PUTCHAR(0x1f) < 0 + || WRITE_TIMEOUT(hello_buffer, sizeof(hello_buffer)) < 0 + || PUTCHAR(((unsigned int) hello_crc >> 8) & 0xff) < 0 + || PUTCHAR(((unsigned int) hello_crc ) & 0xff) < 0 ) + { + state = YS_Error; + break; + } + + timer_set(&wait_timer, 40); + state = YS_WaitResp; + break; + + case YS_WaitResp: + if( timer_expired(wait_timer) ) + { + log("time out waiting for response"); + state = YS_Error; + break; + } + + if( (rc = GETCHAR(1)) < 0 ) + { + if( rc != TTY_TIMEOUT ) + { + state = YS_Error; + break; + } + } + else if( rc == XON || rc == XOFF ) + { + /* Do nothing. Drop them down */ + } + else if( rc == '?' || rc == ENQ ) + { + if( rc == '?' ) + log("remote failed to receive our HELLO packet"); + state = YS_SendHello; + } + else if( rc == ACK ) + { + state = YS_Done; + } + break; + + case YS_Done: + return 0; + + case YS_Error: + return -1; + } + } + + return -1; /* UNREACHABLE */ +} + +int yoohoo_recv_hello(s_yoohoo_sysinfo *remote_data) +{ + char hello_buffer[YOOHOO_HELLOLEN]; + int crc_local = 0; + int crc_remote = 0; + YooHoo_RecvState state = YR_Init; + time_t wait_timer; + time_t junk_timer; + int hello_pos; + int tries = 0; + int rc; + + ASSERT(remote_data); + + while(1) + { + switch(state) { + case YR_Init: + tries = 0; + memset(hello_buffer, '\0', sizeof(hello_buffer)); + state = YR_SendENQ; + break; + + case YR_SendENQ: + if( ++tries > 3 ) + { + log("too many tries receiving hello"); + state = YR_Error; + break; + } + else if( tries > 1 ) + log("yoohoo hello recv - retry %d", tries); + + if( PUTCHAR(ENQ) < 0 ) + { + state = YR_Error; + break; + } + + timer_set(&wait_timer, 120); + state = YR_WaitHeader; + break; + + case YR_WaitHeader: + if( timer_expired(wait_timer) ) + { + log("time out waiting for response"); + state = YR_Error; + break; + } + + if( (rc = GETCHAR(1)) < 0 ) + { + if( rc != TTY_TIMEOUT ) + { + state = YR_Error; + break; + } + } + else if( rc == XON || rc == XOFF ) + { + /* Do nothing. Drop them down */ + } + else if( rc == 0x1f ) + { + state = YR_RecvHello; + } + else + { + timer_set(&junk_timer, 10); + state = YR_TossJunk; + } + break; + + case YR_TossJunk: + if( timer_expired(junk_timer) ) + { + state = YR_SendENQ; + break; + } + + if( (rc = GETCHAR(1)) < 0 ) + { + if( rc != TTY_TIMEOUT ) + { + state = YR_Error; + break; + } + } + else if( rc == XON || rc == XOFF ) + { + /* Do nothing. Drop them down */ + } + else if( rc == 0x1f ) + { + state = YR_RecvHello; + } + break; + + case YR_RecvHello: + hello_pos = 0; + while( (rc = GETCHAR(30)) >= 0 ) + { + if( hello_pos < 128 ) + { + hello_buffer[hello_pos++] = rc; + } + else if( hello_pos == 128 ) + { + crc_remote = ((unsigned int) ((unsigned char) rc) << 8); + ++hello_pos; + } + else if( hello_pos == 129 ) + { + crc_remote |= (unsigned int) ((unsigned char) rc); + break; + } + else + break; + } + + if( hello_pos != 129 ) + { + state = YR_Error; + break; + } + + /* + * Check CRC-16 + */ + crc_local = getcrc16xmodem(hello_buffer, sizeof(hello_buffer)); + if( crc_local != crc_remote ) + { + log("got hello packet with incorrect checksum"); + state = YR_SendNAK; + break; + } + + if( yoohoo_get_hello(remote_data, hello_buffer) ) + { + log("got invalid hello packet"); + state = YR_SendNAK; + } + else + state = YR_SendACK; + break; + + case YR_SendNAK: + if( PUTCHAR('?') < 0 ) + state = YR_Error; + else + state = YR_WaitHeader; + break; + + case YR_SendACK: + if( PUTCHAR(ACK) < 0 ) + state = YR_Error; + else + state = YR_Done; + break; + + case YR_Done: + return 0; + + case YR_Error: + return -1; + } + } + + return -1; /* UNREACHABLE */ +} + +void yoohoo_set_sysinfo(s_yoohoo_sysinfo *local_data, int hrc, + e_protocol protocol) +{ + s_cval_entry *addr_ptr; + s_faddr *primary = NULL; + + const long options = conf_options(cf_options); + const char *p_system = conf_string(cf_system_name); + const char *p_sysop = conf_string(cf_sysop_name); + + memset(local_data, '\0', sizeof(s_yoohoo_sysinfo)); + + /* Set best primary address */ + primary = session_get_bestaka(state.node.addr); + + /* + * Set our local address + */ + if( primary ) + session_addrs_add(&local_data->addrs, &local_data->anum, *primary); + else if( (addr_ptr = conf_first(cf_address)) ) + session_addrs_add(&local_data->addrs, &local_data->anum, addr_ptr->d.falist.addr); + + if( !local_data->anum ) + log("warning: no addresses will be presented to remote"); + + /* + * Set session password + */ + if( state.caller ) + { + session_get_password(state.node.addr, + local_data->passwd, sizeof(local_data->passwd)); + } + else if( hrc == HRC_OK ) + { + /* Satisfy remote with their password */ + const char *p = state.handshake->remote_password(state.handshake); + if( p ) + strnxcpy(local_data->passwd, p, sizeof(local_data->passwd)); + } + + if( !state.caller ) + { + if( state.reqstat != REQS_ALLOW ) + local_data->capabilities |= YOOHOO_WZ_FREQ; + } + + /* compatibility codes */ + if( state.caller ) + { + if( (options & OPTIONS_NO_ZMODEM) != OPTIONS_NO_ZMODEM ) + local_data->capabilities |= YOOHOO_ZMODEM; + if( (options & OPTIONS_NO_ZEDZAP) != OPTIONS_NO_ZEDZAP ) + local_data->capabilities |= YOOHOO_ZEDZAP; + if( (options & OPTIONS_NO_JANUS) != OPTIONS_NO_JANUS ) + local_data->capabilities |= YOOHOO_JANUS; + if( (options & OPTIONS_NO_HYDRA) != OPTIONS_NO_HYDRA ) + local_data->capabilities |= YOOHOO_HYDRA; + } + else + { + switch(protocol) { + case PROT_ZMODEM: local_data->capabilities |= YOOHOO_ZMODEM; break; + case PROT_ZEDZAP: local_data->capabilities |= YOOHOO_ZEDZAP; break; + case PROT_JANUS: local_data->capabilities |= YOOHOO_JANUS; break; + case PROT_HYDRA: local_data->capabilities |= YOOHOO_HYDRA; break; + default: break; + } + } + + local_data->product_code = BF_PRODCODE; + + if( hrc == HRC_BAD_PASSWD ) + { + local_data->version_maj = 99; + local_data->version_min = 99; /* TODO */ + } + else + { + local_data->version_maj = 0; + local_data->version_min = 1; + } + + strnxcpy(local_data->sysop, p_sysop ? p_sysop : "Unknown", sizeof(local_data->sysop)); + + switch(hrc) { + case HRC_BAD_PASSWD: + strnxcpy(local_data->system, "Bad password", sizeof(local_data->system)); + break; + case HRC_LOW_SPEED: + strnxcpy(local_data->system, "Connect speed too low", sizeof(local_data->system)); + break; + case HRC_BUSY: + strnxcpy(local_data->system, "All AKAs are busy", sizeof(local_data->system)); + break; + default: + strnxcpy(local_data->system, p_system ? p_system : "Unknown", sizeof(local_data->system)); + } +} + +/***************************************************************************** + * Write system information to the log + * + * Arguments: + * yoohoo structure with the system information + * + * Return value: + * None + */ +void yoohoo_log_sysinfo(s_yoohoo_sysinfo *yoohoo) +{ + int i; + char abuf[BF_MAXADDRSTR+1]; + + if( yoohoo->anum ) + for( i = 0; i < yoohoo->anum; i++ ) + { + log(" Address : %s", ftn_addrstr(abuf, yoohoo->addrs[i].addr)); + } + else + log(" Address : "); + + if( yoohoo->system[0] ) + log(" System : %s", string_printable(yoohoo->system)); + +#ifdef BFORCE_LOG_PASSWD + if( yoohoo->passwd[0] ) + log(" Password : %s", string_printable(yoohoo->passwd)); +#endif + + if( yoohoo->sysop[0] ) + log(" SysOp : %s", string_printable(yoohoo->sysop)); + + if( yoohoo->product_code || yoohoo->version_maj || yoohoo->version_min ) + { + log(" Mailer : %s [%02x] %d.%d", + "?", yoohoo->product_code, + yoohoo->version_maj, yoohoo->version_min); + } +} + diff --git a/source/bforce/prot_yoohoo_api.c b/source/bforce/prot_yoohoo_api.c new file mode 100644 index 0000000..cff6357 --- /dev/null +++ b/source/bforce/prot_yoohoo_api.c @@ -0,0 +1,363 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "version.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" +#include "session.h" +#include "prot_yoohoo.h" + +void yoohoo_init(s_handshake_protocol *THIS); +void yoohoo_deinit(s_handshake_protocol *THIS); +int yoohoo_incoming(s_handshake_protocol *THIS); +int yoohoo_outgoing(s_handshake_protocol *THIS); +s_faddr *yoohoo_remote_address(s_handshake_protocol *THIS); +char *yoohoo_remote_password(s_handshake_protocol *THIS); +char *yoohoo_remote_sysop_name(s_handshake_protocol *THIS); +char *yoohoo_remote_system_name(s_handshake_protocol *THIS); +char *yoohoo_remote_location(s_handshake_protocol *THIS); +char *yoohoo_remote_phone(s_handshake_protocol *THIS); +char *yoohoo_remote_flags(s_handshake_protocol *THIS); +char *yoohoo_remote_mailer(s_handshake_protocol *THIS); +s_faddr *yoohoo_local_address(s_handshake_protocol *THIS); +char *yoohoo_local_password(s_handshake_protocol *THIS); + +s_handshake_protocol handshake_protocol_yoohoo = { + /* Section 1 */ + "YooHoo", + "", + "", + NULL, + NULL, + 0, + yoohoo_init, + yoohoo_deinit, + yoohoo_incoming, + yoohoo_outgoing, + /* Section 2 */ + yoohoo_remote_address, + yoohoo_remote_password, + yoohoo_remote_sysop_name, + yoohoo_remote_system_name, + NULL, + NULL, + NULL, + NULL, + NULL, + /* Section 3 */ + yoohoo_local_address, + yoohoo_local_password +}; + +void yoohoo_init(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data == NULL); + ASSERT(THIS->local_data == NULL); + + THIS->remote_data = (char *)xmalloc(sizeof(s_yoohoo_sysinfo)); + THIS->local_data = (char *)xmalloc(sizeof(s_yoohoo_sysinfo)); + + memset(THIS->remote_data, '\0', sizeof(s_yoohoo_sysinfo)); + memset(THIS->local_data, '\0', sizeof(s_yoohoo_sysinfo)); +} + +void yoohoo_deinit(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + ASSERT(THIS->local_data); + + if( THIS->remote_data ) + { + memset(THIS->remote_data, '\0', sizeof(s_yoohoo_sysinfo)); + free(THIS->remote_data); + } + + if( THIS->local_data ) + { + memset(THIS->local_data, '\0', sizeof(s_yoohoo_sysinfo)); + free(THIS->local_data); + } +} + +int yoohoo_incoming(s_handshake_protocol *THIS) +{ + int rc = HRC_OK; + s_yoohoo_sysinfo *remote_data = NULL; + s_yoohoo_sysinfo *local_data = NULL; + + ASSERT(THIS); + ASSERT(THIS->remote_data); + ASSERT(THIS->local_data); + + remote_data = (s_yoohoo_sysinfo *)THIS->remote_data; + local_data = (s_yoohoo_sysinfo *)THIS->local_data; + + if( yoohoo_recv_hello(remote_data) ) + return HRC_OTHER_ERR; + + /* + * Check password(s) + */ + if( session_addrs_check(remote_data->addrs, remote_data->anum, + remote_data->passwd, NULL, 0) ) + { + rc = HRC_BAD_PASSWD; + /* Don't return. Send HELLO with + * invalid password messages */ + } + else + { + /* Lock (create BSY) remote addresses */ + if( session_addrs_lock(remote_data->addrs, + remote_data->anum) ) + { + log("all remote addresses are busy"); + rc = HRC_BUSY; + } + else + { + /* + * Fill state.node with a first valid + * address, try to lookup it in nodelist + */ + session_remote_lookup(remote_data->addrs, remote_data->anum); + + if( session_check_speed() ) + rc = HRC_LOW_SPEED; + } + } + + /* + * Put HELLO information to the log + */ + (void)yoohoo_log_sysinfo(remote_data); + + session_remote_log_status(); + + if( rc == HRC_OK ) + { + const long options = conf_options(cf_options); + + /* + * Set inbound directories, ignore errors, + * because we want send mail in any case. + */ + (void)session_set_inbound(); + + /* + * Set protocol that we will use + */ + if( (remote_data->capabilities & YOOHOO_HYDRA) + && !(options & OPTIONS_NO_HYDRA) ) + THIS->protocol = PROT_HYDRA; + else if( (remote_data->capabilities & YOOHOO_ZEDZAP) + && !(options & OPTIONS_NO_ZEDZAP) ) + THIS->protocol = PROT_ZEDZAP; + else if( (remote_data->capabilities & YOOHOO_ZMODEM) + && !(options & OPTIONS_NO_ZMODEM) ) + THIS->protocol = PROT_ZMODEM; + else /* NCP */ + { + THIS->protocol = PROT_NOPROT; + rc = HRC_NO_PROTOS; + } + + /* + * Create mail/files queue + */ + session_create_files_queue(remote_data->addrs, remote_data->anum); + + /* + * Set FREQ processor status + */ + if( rc == HRC_OK && THIS->protocol != PROT_NOPROT ) + session_set_freqs_status(); + else + state.reqstat = REQS_DISABLED; + } + + /* + * Prepare ``local_data'' structure + */ + (void)yoohoo_set_sysinfo(local_data, rc, THIS->protocol); + + if( yoohoo_send_hello(local_data) && rc == HRC_OK ) + rc = HRC_OTHER_ERR; + + return rc; +} + +int yoohoo_outgoing(s_handshake_protocol *THIS) +{ + s_yoohoo_sysinfo *remote_data = NULL; + s_yoohoo_sysinfo *local_data = NULL; + + ASSERT(THIS); + ASSERT(THIS->remote_data); + ASSERT(THIS->local_data); + + remote_data = (s_yoohoo_sysinfo *)THIS->remote_data; + local_data = (s_yoohoo_sysinfo *)THIS->local_data; + + /* + * Set FREQ processor status + */ + session_set_freqs_status(); + + /* + * Prepare ``local_data'' structure + */ + (void)yoohoo_set_sysinfo(local_data, HRC_OK, THIS->protocol); + + if( yoohoo_send_hello(local_data) ) + return HRC_OTHER_ERR; + + if( yoohoo_recv_hello(remote_data) ) + return HRC_OTHER_ERR; + + /* + * Put EMSI information to the log + */ + (void)yoohoo_log_sysinfo(remote_data); + + /* + * Make sure expected address was presented + */ + if( session_addrs_check_genuine(remote_data->addrs, + remote_data->anum, + state.node.addr) ) + return HRC_NO_ADDRESS; + + /* + * Check password(s) + */ + if( session_addrs_check(remote_data->addrs, remote_data->anum, + remote_data->passwd, NULL, 0) ) + return HRC_BAD_PASSWD; + + /* + * Lock (create BSY) remote addresses + */ + (void)session_addrs_lock(remote_data->addrs, + remote_data->anum); + + /* + * Set protocol we will use ("options" ignored) + */ + if( remote_data->capabilities & YOOHOO_HYDRA ) + THIS->protocol = PROT_HYDRA; + else if( remote_data->capabilities & YOOHOO_JANUS ) + THIS->protocol = PROT_JANUS; + else if( remote_data->capabilities & YOOHOO_ZEDZAP ) + THIS->protocol = PROT_ZEDZAP; + else if( remote_data->capabilities & YOOHOO_ZMODEM ) + THIS->protocol = PROT_ZMODEM; + else + return HRC_NO_PROTOS; + + /* + * Show remote status (prot/unprot, listed/unlisted) + */ + session_remote_log_status(); + + /* + * Set inbound directories + */ + if( session_set_inbound() ) + return HRC_OTHER_ERR; + + /* + * Check EMSI flags and set corresponding local HOLD flags + */ + (void)session_set_send_options(); + + /* + * Create mail/files queue + */ + session_create_files_queue(remote_data->addrs, + remote_data->anum); + + return HRC_OK; +} + +s_faddr *yoohoo_remote_address(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_yoohoo_sysinfo *)THIS->remote_data)->anum > 0 ) + return &((s_yoohoo_sysinfo *)THIS->remote_data)->addrs[0].addr; + + return NULL; +} + +char *yoohoo_remote_password(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_yoohoo_sysinfo *)THIS->remote_data)->passwd[0] ) + return ((s_yoohoo_sysinfo *)THIS->remote_data)->passwd; + + return NULL; +} + +char *yoohoo_remote_sysop_name(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_yoohoo_sysinfo *)THIS->remote_data)->sysop[0] ) + return ((s_yoohoo_sysinfo *)THIS->remote_data)->sysop; + + return NULL; +} + +char *yoohoo_remote_system_name(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->remote_data); + + if( ((s_yoohoo_sysinfo *)THIS->remote_data)->system[0] ) + return ((s_yoohoo_sysinfo *)THIS->remote_data)->system; + + return NULL; +} + +s_faddr *yoohoo_local_address(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->local_data); + + if( ((s_yoohoo_sysinfo *)THIS->local_data)->anum > 0 ) + return &((s_yoohoo_sysinfo *)THIS->local_data)->addrs[0].addr; + + return NULL; +} + +char *yoohoo_local_password(s_handshake_protocol *THIS) +{ + ASSERT(THIS); + ASSERT(THIS->local_data); + + if( ((s_yoohoo_sysinfo *)THIS->local_data)->passwd[0] ) + return ((s_yoohoo_sysinfo *)THIS->local_data)->passwd; + + return NULL; +} + diff --git a/source/bforce/prot_zmmisc.c b/source/bforce/prot_zmmisc.c new file mode 100644 index 0000000..21b9fd1 --- /dev/null +++ b/source/bforce/prot_zmmisc.c @@ -0,0 +1,1180 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "io.h" +#include "prot_zmodem.h" + +int Z_Rxexp; /* True means timer expired */ +int Z_Rxtout; /* Seconds to wait for receiving whole block */ +int Z_Rxwait; /* Seconds to wait for character available */ +int Z_Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ +int Z_Rxtype; /* Type of header received */ +int Z_Rxcount; /* Count of data bytes received */ +int Z_Txnulls; /* Number of nulls to send at beginning of ZDATA hdr */ +char Z_Rxhdr[4]; /* Received header */ +char Z_Txhdr[4]; /* Transmitted header */ +long Z_Rxpos; /* Received file position */ +int Z_Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ +int Z_Txcrc32; /* Display flag indicating 32 bit CRC being sent */ +int Z_Rxcrc32; /* Display flag indicating 32 bit CRC being received */ +char Z_Attn[ZATTNLEN+1];/* Attention string rx sends to tx on err */ +int Z_Ctlesc; /* Encode control characters */ +int Z_Lastsent; /* Character we sent last */ + +#ifdef DEBUG +static const char *FrameTypes[] = +{ + "Unused", /* (-7) */ + "Unused", /* (-6) */ + "CRC error", /* ZCRCERR (-5) */ + "Bad frame", /* ZERROR (-4) */ + "I/O Error", /* ZEXIT (-3) */ + "Carrier Lost", /* ZHANGUP (-2) */ + "Timer out", /* ZTIMER (-1) */ +#define FTOFFSET 7 + "ZRQINIT", + "ZRINIT", + "ZSINIT", + "ZACK", + "ZFILE", + "ZSKIP", + "ZNAK", + "ZABORT", + "ZFIN", + "ZRPOS", + "ZDATA", + "ZEOF", + "ZFERR", + "ZCRC", + "ZCHALLENGE", + "ZCOMPL", + "ZCAN", + "ZFREECNT", + "ZCOMMAND", + "ZSTDERR", + "Unused" +#define FRTYPES 22 /* Total number of frame types in this array */ + /* not including psuedo negative entries */ +}; +#endif + +static int zrbhdr16(char *hdr); +static int zrbhdr32(char *hdr); +static int zrhhdr(char *hdr); +static int zrdat32(char *buf, int length, long pos); +static int zrdat16(char *buf, int length, long pos); +static int zgethex(void); +static int noxrd7(void); +static int zdlread(void); +static int zputhex(int c); +static void zsendline_init(char *); + +static void zalarmh(int sig_no) +{ + DEB((D_PROT, "zalarmh: got SIGALRM (timer expired!)")); + Z_Rxexp = 1; +} + +void setalarm(int sec) +{ + static int allready = 0; + + if( !sec ) + { + alarm(0); return; + } + + Z_Rxexp = 0; + + if( allready == 0 ) + { + if( signal(SIGALRM, zalarmh) == SIG_ERR ) + { + logerr("can't setup SIGALRM handler"); + return; + } + allready = 1; + } + + alarm(sec); +} + +/* ------------------------------------------------------------------------- */ +/* Read a byte, checking for ZMODEM escape encoding */ +/* including five CAN which represents a quick abort */ +/* ------------------------------------------------------------------------- */ +static int zmodem_getbyte(void) +{ + int c; + int cancount = 0; + int gotdle = 0; + + while(1) + { + if( Z_Rxexp ) + return ZTIMER; + + if( (c = GETCHAR(Z_Rxwait)) < 0 ) + return c; + + if( gotdle ) + { + if( c != CAN ) + cancount = 0; + + switch( c ) { + case CAN: + if( ++cancount > 5 ) + return GOTCAN; + break; + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + return c|GOTOR; + case ZRUB0: + return 0177; + case ZRUB1: + return 0377; + case XON: + case XOFF: + case XON|0200: + case XOFF|0200: + break; + default: + if( !Z_Ctlesc || (c & 140) ) + { + if( (c & 0140) == 0100 ) + return c^0100; + else + log("zmodem: got bad escape sequence 0x%x", c); + } + } + } + else + { + switch(c) { + case ZDLE: + gotdle = 1; + break; + case XON: + case XOFF: + case XON|0200: + case XOFF|0200: + break; + default: + if( !Z_Ctlesc || (c & 0140) ) + { + return c; + } + } + } + } + + return 0; +} + +static int zmodem_getbyte_raw(void) +{ + int c; + + while(1) + { + if( Z_Rxexp ) + return ZTIMER; + + if( (c = GETCHAR(Z_Rxwait)) < 0 ) + return c; + + c &= 0177; + + switch(c) { + case XON: + case XOFF: + break; + case '\r': + case '\n': + case ZDLE: + return c; + default: + if( !Z_Ctlesc || (c & 0140) ) + return c; + } + } + + return 0; +} + +static int zmodem_putbyte(int c) +{ + static int last_esc = -2; + static char tab[256]; + int rc; + + if( Z_Ctlesc != last_esc ) + { + zsendline_init(tab); + last_esc = Z_Ctlesc; + } + + switch( tab[(unsigned char)(c)] ) { + case 0: + if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 ) + return rc; + break; + + case 1: + if( (rc = BUFCHAR(ZDLE)) < 0 ) + return rc; + c ^= 0100; + if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 ) + return rc; + break; + + case 2: + /* Escape for telnet escape sequence */ + if( (Z_Lastsent & 0177) != '@' ) + { + if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 ) + return rc; + } + else + { + c ^= 0100; + if( (rc = BUFCHAR(ZDLE)) < 0 ) + return rc; + if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 ) + return rc; + } + break; + + default: + ASSERT_MSG(); + } + + return ZOK; +} + +static int zdlread(void) +{ + int c, cancnt = 0; + + /* Quick check for non control characters */ + for(;;) + { + if( Z_Rxexp ) + return(ZTIMER); + + c = GETCHAR(Z_Rxwait); + + if( (c & 0140) || (c < 0) ) + return(c); + + switch( c ) { + case ZDLE: + break; + case XON: + case XOFF: + case XON|0200: + case XOFF|0200: + continue; + default: + if( Z_Ctlesc && !(c & 0140) ) + continue; + return(c); + } + break; + } + + for(;;) + { + if( Z_Rxexp ) + return(ZTIMER); + + if( (c = GETCHAR(Z_Rxwait)) < 0 ) + return(c); + + if( c != CAN ) + cancnt = 0; + + switch( c ) { + case CAN: + if( ++cancnt >= 5 ) + return(GOTCAN); + continue; + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + return(c | GOTOR); + case ZRUB0: + return(0177); + case ZRUB1: + return(0377); + case XON: + case XOFF: + case XON|0200: + case XOFF|0200: + continue; + default: + if( Z_Ctlesc && !(c & 0140) ) + continue; + if( (c & 0140) == 0100 ) + return(c^0100); + + /* It was unknown escape sequence */ + DEB((D_PROT, "zdlread: bad escape sequence 0x%x", c)); + + return(ZERROR); + } + } +} + +/* ------------------------------------------------------------------------- */ +/* Read a character from the modem line with timeout. */ +/* Eat parity, XON and XOFF characters. */ +/* ------------------------------------------------------------------------- */ +static int noxrd7(void) +{ + int c; + + for(;;) + { + if( Z_Rxexp ) + return(ZTIMER); + + if( (c = GETCHAR(Z_Rxwait)) < 0 ) + return(c); + + switch( c &= 0177 ) { + case XON: + case XOFF: + continue; + default: + if( Z_Ctlesc && !(c & 0140) ) + continue; + case '\r': + case '\n': + case ZDLE: + return(c); + } + } +} + +/* ------------------------------------------------------------------------- */ +/* Send character $c with ZMODEM escape sequence encoding. */ +/* Escape XON, XOFF. Escape CR following @ (Telenet net escape) */ +/* Warning: Put result to buffer with BUFCHAR function! Use FLUSHBUF later! */ +/* ------------------------------------------------------------------------- */ +int zsendline(char c) +{ + static int last_esc = -2; + static char tab[256]; + int rc; + + if( Z_Ctlesc != last_esc ) + { + zsendline_init(tab); + last_esc = Z_Ctlesc; + } + + switch( tab[(unsigned char)(c)] ) { + case 0: + if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 ) + return(rc); + break; + case 1: + if( (rc = BUFCHAR(ZDLE)) < 0 ) + return(rc); + c ^= 0100; + if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 ) + return(rc); + break; + case 2: + /* Escape for telnet escape sequence */ + if( (Z_Lastsent & 0177) != '@' ) + { + if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 ) + return(rc); + } + else + { + c ^= 0100; + if( (rc = BUFCHAR(ZDLE)) < 0 ) + return(rc); + if( (rc = BUFCHAR(Z_Lastsent = c)) < 0 ) + return(rc); + } + break; + } + + return(ZOK); +} + +/* ------------------------------------------------------------------------- */ +/* Send ZMODEM binary header hdr of type $type */ +/* ------------------------------------------------------------------------- */ +int zsbhdr(int type, char *hdr) +{ + int n, rc; + unsigned short crc; + unsigned long crc32; + + DEB((D_PROT, "zsbhdr: %s %lx (CRC%s)", FrameTypes[type+FTOFFSET], + rclhdr(hdr), Z_Txfcs32?"32":"16")); + + if( type == ZDATA ) + for( n=Z_Txnulls; --n >= 0; ) + { + if( (rc = BUFCHAR('\0')) < 0 ) + return(rc); + } + + if( (rc = BUFCHAR(ZPAD)) < 0 ) + return(rc); + if( (rc = BUFCHAR(ZDLE)) < 0 ) + return(rc); + + Z_Txcrc32 = Z_Txfcs32; + + if( Z_Txcrc32 ) + { + /* Use CRC32 */ + crc32 = 0xFFFFFFFFL; + + if( (rc = BUFCHAR(ZBIN32)) < 0 ) + return(rc); + if( (rc = zsendline(type)) < 0 ) + return(rc); + crc32 = updcrc32(type, crc32); + + for( n = 4; --n >= 0; ++hdr ) + { + crc32 = updcrc32((0377 & *hdr), crc32); + if( (rc = zsendline((*hdr) & 0377)) < 0 ) + return(rc); + } + + crc32 = ~crc32; + + for( n = 4; --n >= 0; ) + { + if( (rc = zsendline(crc32 & 0377)) < 0 ) + return(rc); + crc32 >>= 8; + } + } + else /* CRC-16 */ + { + crc = 0; + + if( (rc = BUFCHAR(ZBIN)) < 0 ) + return rc; + if( (rc = zsendline(type)) < 0 ) + return(rc); + crc = updcrc16(type, crc); + + for( n = 4; --n >= 0; ++hdr ) + { + if( (rc = zsendline((*hdr) & 0377)) < 0 ) + return(rc); + crc = updcrc16(((*hdr) & 0377), crc); + } + + crc = updcrc16(0,updcrc16(0,crc)); + if( (rc = zsendline((crc>>8) & 0377)) < 0 ) + return(rc); + if( (rc = zsendline((crc ) & 0377)) < 0 ) + return(rc); + } + + if( (rc = FLUSHBUF()) < 0 ) + return(rc); + if( type != ZDATA && (rc = FLUSHOUT()) < 0 ) + return rc; + + return(0); +} + +/* ------------------------------------------------------------------------- */ +/* Send ZMODEM HEX header hdr of type $type */ +/* ------------------------------------------------------------------------- */ +int zshhdr(int type, char *hdr) +{ + int n, rc; + unsigned short crc; + + DEB((D_PROT, "zshhdr: %s %lx (CRC16)", + FrameTypes[(type & 0x7f)+FTOFFSET], rclhdr(hdr))); + + Z_Txcrc32 = 0; + + if( (rc = BUFCHAR(ZPAD)) < 0 ) return(rc); + if( (rc = BUFCHAR(ZPAD)) < 0 ) return(rc); + if( (rc = BUFCHAR(ZDLE)) < 0 ) return(rc); + if( (rc = BUFCHAR(ZHEX)) < 0 ) return(rc); + if( (rc = zputhex(type)) < 0 ) return(rc); + + crc = updcrc16(type, 0); + for( n = 4; --n >= 0; ++hdr ) + { + if( (rc = zputhex(*hdr & 0377)) < 0 ) + return(rc); + crc = updcrc16((*hdr & 0377), crc); + } + + crc = updcrc16(0, updcrc16(0,crc)); + if( (rc = zputhex((crc>>8)&0377)) < 0 ) return(rc); + if( (rc = zputhex((crc )&0377)) < 0 ) return(rc); + + /* Make it printable on remote machine */ + if( (rc = BUFCHAR('\r')) < 0 ) return(rc); + if( (rc = BUFCHAR('\n')) < 0 ) return(rc); + + /* Uncork the remote in case a fake XOFF has stopped data flow */ + if( type != ZFIN && type != ZACK ) + { + if( (rc = BUFCHAR(XON)) < 0 ) + return(rc); + } + + if( (rc = FLUSHBUF()) < 0 ) return(rc); + if( (rc = FLUSHOUT()) < 0 ) return(rc); + + return(0); +} + +/* ------------------------------------------------------------------------- */ +/* Send binary array buf of length length, with ending ZDLE sequence frameend*/ +/* $pos must point to current offset of sending file (for logging only) */ +/* ------------------------------------------------------------------------- */ +#ifdef DEBUG +static const char *Zendnames[] = {"ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"}; +#endif + +int zsdata(const char *buf, int length, int frameend, long pos) +{ + int n, rc; + unsigned short crc; + unsigned long crc32; + + DEB((D_PROT, "zsdata: %d %s (CRC%s) from %d pos", length, + Zendnames[(frameend-ZCRCE)&3], Z_Txcrc32?"32":"16", pos)); + + if( Z_Txcrc32 ) + { + crc32 = 0xFFFFFFFFL; + + for( ; --length >= 0; ++buf ) + { + if( (rc = zsendline((*buf) & 0377)) < 0 ) + return(rc); + crc32 = updcrc32(((*buf) & 0377), crc32); + } + + if( (rc = BUFCHAR(ZDLE)) < 0 ) + return(rc); + if( (rc = BUFCHAR(frameend)) < 0 ) + return(rc); + crc32 = updcrc32(frameend, crc32); + + crc32 = ~crc32; + for( n = 4; --n >= 0; ) + { + if( (rc = zsendline(crc32 & 0377)) < 0 ) + return(rc); + crc32 >>= 8; + } + } + else /* CRC-16 */ + { + crc = 0; + for( ; --length >= 0; ++buf ) + { + if( (rc = zsendline((*buf) & 0377)) < 0 ) + return(rc); + crc = updcrc16((*buf & 0377), crc); + } + + if( (rc = BUFCHAR(ZDLE)) < 0 ) + return(rc); + if( (rc = BUFCHAR(frameend)) < 0 ) + return(rc); + crc = updcrc16(frameend, crc); + + crc = updcrc16(0, updcrc16(0, crc)); + if( (rc = zsendline((crc>>8) & 0377)) < 0 + || (rc = zsendline((crc ) & 0377)) < 0 ) + return(rc); + } + + if( (rc = FLUSHBUF()) < 0 ) + return(rc); + + if( frameend == ZCRCW ) + { + if( (rc = PUTCHAR(XON)) < 0 ) + return(rc); + if( (rc = FLUSHOUT()) < 0 ) + return(rc); + } + + return(0); +} + +/* ------------------------------------------------------------------------- */ +/* Receive array buf of max length+1 with ending ZDLE sequence */ +/* and CRC. Returns the ending character or error code. */ +/* $pos must contatain current offset of receiving file (for logging only!) */ +/* ------------------------------------------------------------------------- */ +int zrdata(char *buf, int length, long pos) +{ + return (Z_Rxframeind == ZBIN32) ? zrdat32(buf, length, pos) + : zrdat16(buf, length, pos); +} + +static int zrdat16(char *buf, int length, long pos) +{ + int c; + unsigned short crc; + char *end; + int d; + + Z_Rxcount = 0; + crc = 0; + end = buf + length; + + while( buf <= end ) + { + if( (c=zdlread()) & ~0377 ) + { +switch_again: + switch( c ) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; + c &= 0377; + crc = updcrc16(c, crc); + + if( (c=zdlread()) & ~0377 ) goto switch_again; + crc = updcrc16(c, crc); + + if( (c=zdlread()) & ~0377 ) goto switch_again; + crc = updcrc16(c, crc); + + Z_Rxcount = length - (end - buf); + + if( crc & 0xFFFF ) + { + DEB((D_PROT, "zrdat16: %d %s : Bad CRC", + Z_Rxcount, Zendnames[(d-GOTCRCE)&3]));; + log("ZDATA with bad CRC"); + + return ZCRCERR; + } + + DEB((D_PROT, "zrdat16: %d %s (CRC16) at %d pos", + Z_Rxcount, Zendnames[(d-GOTCRCE)&3], pos)); + + return d; + + case GOTCAN: + DEB((D_PROT, "zrdat16: Sender CANceled")); + return ZCAN; + + case ZHANGUP: + case ZTIMER: + case ZEXIT: + DEB((D_PROT, "zrdat16: zdlread() return %s", + ( c == ZHANGUP ) ? "ZHANGUP": + ( c == ZEXIT ) ? "ZEXIT": + ( c == ZTIMER ) ? "ZTIMER" : "Unknown")); + return c; + + default: + DEB((D_PROT, "zrdat16: $zdlread return %d", c)); + return c; + } + } + *buf++ = c; + crc = updcrc16(c, crc); + } + + log("zmodem: data packet too long"); + DEB((D_PROT, "zrdat16: data packet too long")); + + return ZERROR; +} + +static int zrdat32(char *buf, int length, long pos) +{ + int c, d; + unsigned long crc; + char *end; + + Z_Rxcount = 0; + crc = 0xFFFFFFFFL; + end = buf + length; + + while( buf <= end ) + { + if( (c = zdlread()) & ~0377 ) + { +switch_again: + switch( c ) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; + c &= 0377; + crc = updcrc32(c, crc); + if( (c = zdlread()) & ~0377 ) goto switch_again; + crc = updcrc32(c, crc); + + if( (c = zdlread()) & ~0377 ) goto switch_again; + crc = updcrc32(c, crc); + + if( (c = zdlread()) & ~0377 ) goto switch_again; + crc = updcrc32(c, crc); + + if( (c = zdlread()) & ~0377 ) goto switch_again; + crc = updcrc32(c, crc); + + Z_Rxcount = length - (end - buf); + + if( crc != 0xDEBB20E3 ) + { + DEB((D_PROT, "zrdat32: %d %s : Bad CRC", + Z_Rxcount, Zendnames[(d-GOTCRCE)&3])); + log("DATA with bad CRC"); + + return ZCRCERR; + } + + DEB((D_PROT, "zrdat32: %d %s (CRC32) at %d pos", + Z_Rxcount, Zendnames[(d-GOTCRCE)&3], pos)); + + return d; + + case GOTCAN: + DEB((D_PROT, "zrdat32: Sender CANceled")); + return ZCAN; + + case ZEXIT: + case ZTIMER: + case ZHANGUP: + DEB((D_PROT, "zrdat32: zdlread() return %s", + ( c == ZHANGUP ) ? "ZHANGUP": + ( c == ZEXIT ) ? "ZEXIT": + ( c == ZTIMER ) ? "ZTIMER" : "Unknown")); + return c; + + default: + DEB((D_PROT, "zrdat32: $zdlread return %d", c)); + return c; + } + } + *buf++ = c; + crc = updcrc32(c, crc); + } + + log("zmodem: data packet too long"); + DEB((D_PROT, "zrdat32: data packet too long")); + + return ZERROR; +} + +/* ------------------------------------------------------------------------- */ +/* Read a ZMODEM header to hdr, either binary or hex. */ +/* On success, set Z_Rxpos and return type of header. */ +/* Otherwise return negative on error. */ +/* Return ZERROR instantly if ZCRCW sequence, for fast error recovery. */ +/* ------------------------------------------------------------------------- */ +int zgethdr(char *hdr) +{ + int c, n, cancount; + + n = 8192; /* Maximum number of garbage chars */ + cancount = 5; /* CANcel on this can number */ + + Z_Rxframeind = 0; + Z_Rxtype = 0; + +again: + if( Z_Rxexp ) { c = ZTIMER; goto fifi; } + + switch( c = GETCHAR(Z_Rxwait) ) { + case ZEXIT: + case ZHANGUP: + case ZTIMER: + goto fifi; + case CAN: +gotcan: + if( --cancount == 0 ) + { + c = ZCAN; goto fifi; + } + + if( Z_Rxexp ) { c = ZTIMER; goto fifi; } + + switch( c = GETCHAR(Z_Rxwait) ) { + case ZCRCW: + /* Return immediate ERROR if ZCRCW sequence seen */ + c = ZERROR; + case ZEXIT: + case ZHANGUP: + case ZTIMER: + goto fifi; + default: + break; + case CAN: + if( --cancount == 0 ) + { + c = ZCAN; goto fifi; + } + goto again; + } + default: + if( --n == 0 ) { + DEB((D_PROT, "zgethdr: garbage count exceeded")); + c = ZERROR; goto fifi; + } + cancount = 5; + goto again; + case ZPAD|0200: /* This is what we want. */ + case ZPAD: /* This is what we want. */ + break; + } + cancount = 5; + +splat: + switch( c = noxrd7() ) { + case ZPAD: + goto splat; + case ZEXIT: + case ZHANGUP: + case ZTIMER: + goto fifi; + default: + if( --n == 0 ) { + DEB((D_PROT, "zgethdr: garbage count exceeded")); + c = ZERROR; goto fifi; + } + goto again; + case ZDLE: /* This is what we want. */ + break; + } + + switch( c=noxrd7() ) { + case ZEXIT: + case ZHANGUP: + case ZTIMER: + goto fifi; + case ZBIN: + /* receive binary header with crc16 */ + Z_Rxcrc32 = 0; + Z_Rxframeind = ZBIN; + c = zrbhdr16(hdr); + break; + case ZBIN32: + /* receive binary header with crc32 */ + Z_Rxcrc32 = 1; + Z_Rxframeind = ZBIN32; + c = zrbhdr32(hdr); + break; + case ZHEX: + /* receive hex header (all hex headers have crc16) */ + Z_Rxcrc32 = 0; + Z_Rxframeind = ZHEX; + c = zrhhdr(hdr); + break; + case CAN: + goto gotcan; + default: + if( --n == 0 ) { + DEB((D_PROT, "zgethdr: garbage count exceeded")); + c = ZERROR; goto fifi; + } + goto again; + } + + if( c >= 0 ) + { + Z_Rxpos = hdr[ZP3] & 0377; + Z_Rxpos = (Z_Rxpos<<8) + (hdr[ZP2] & 0377); + Z_Rxpos = (Z_Rxpos<<8) + (hdr[ZP1] & 0377); + Z_Rxpos = (Z_Rxpos<<8) + (hdr[ZP0] & 0377); + } + +fifi: + if( c == GOTCAN ) + c = ZCAN; + +#ifdef DEBUG + if( (c >= -7) && (c <= FRTYPES) ) + DEB((D_PROT, "zgethdr: %s %lx", FrameTypes[c+FTOFFSET], Z_Rxpos)); + else + DEB((D_PROT, "zgethdr: %d %lx", c, Z_Rxpos)); +#endif + + return(c); +} + +/* ------------------------------------------------------------------------- */ +/* Receive a binary style header (type and position) */ +/* ------------------------------------------------------------------------- */ +static int zrbhdr16(char *hdr) +{ + int c, n; + unsigned short crc; + + if( (c = zdlread()) < 0 ) + return(c); + Z_Rxtype = c; + crc = updcrc16(c, 0); + + for( n = 4; --n >= 0; ++hdr ) + { + if( (c = zdlread()) < 0 ) + return(c); + crc = updcrc16(c, crc); + *hdr = c; + } + + if( (c = zdlread()) < 0 ) + return(c); + crc = updcrc16(c, crc); + + if( (c = zdlread()) < 0 ) + return(c); + crc = updcrc16(c, crc); + + if( crc & 0xFFFF ) + { + DEB((D_PROT, "zrbhdr: Bad CRC")); + log("Bad CRC"); + return(ZCRCERR); + } + + return(Z_Rxtype); +} + +/* ------------------------------------------------------------------------- */ +/* Receive a binary style header (type and position) with 32 bit FCS */ +/* ------------------------------------------------------------------------- */ +static int zrbhdr32(char *hdr) +{ + int c, n; + unsigned long crc; + + if( (c = zdlread()) < 0 ) + return c; + Z_Rxtype = c; + crc = 0xFFFFFFFFL; + crc = updcrc32(c, crc); + + for( n = 4; --n >= 0; ++hdr ) + { + if( (c = zdlread()) < 0 ) + return(c); + crc = updcrc32(c, crc); + *hdr = c; + } + + for( n = 4; --n >= 0; ) + { + if( (c = zdlread()) < 0 ) + return(c); + crc = updcrc32(c, crc); + } + + if( crc != 0xDEBB20E3 ) + { + DEB((D_PROT, "zrbhdr32: Bad CRC")); + log("Bad CRC"); + return(ZCRCERR); + } + + return(Z_Rxtype); +} + + +/* ------------------------------------------------------------------------- */ +/* Receive a hex style header (type and position) */ +/* ------------------------------------------------------------------------- */ +static int zrhhdr(char *hdr) +{ + int c, n; + unsigned short crc; + + if( (c = zgethex()) < 0 ) + return(c); + Z_Rxtype = c; crc = updcrc16(c, 0); + + for( n = 4; --n >= 0; ) + { + if( (c = zgethex()) < 0 ) + return(c); + crc = updcrc16(c, crc); + *hdr++ = c; + } + + if( (c = zgethex()) < 0 ) + return(c); + crc = updcrc16(c, crc); + + if( (c = zgethex()) < 0 ) + return(c); + crc = updcrc16(c, crc); + + if( crc & 0xFFFF ) + { + DEB((D_PROT, "zrhhdr: Bad CRC")); + log("Bad CRC"); + return(ZCRCERR); + } + + if( CHARWAIT(0) ) + { + /* There is some characters available.. */ + + switch( (c = GETCHAR(1)) ) { + case 0215: + case 015: + /* Throw away possible cr/lf */ + if( (c = GETCHAR(1)) < 0 && c != ZTIMER ) + return(c); + break; + case ZEXIT: + case ZHANGUP: + return(c); + } + } + + return(Z_Rxtype); +} + +/* ------------------------------------------------------------------------- */ +/* Write a byte as two hex digits */ +/* ------------------------------------------------------------------------- */ +static int zputhex(int c) +{ + static char digits[] = "0123456789abcdef"; + int rc; + + if( (rc = BUFCHAR(digits[(c&0xF0)>>4])) < 0 + || (rc = BUFCHAR(digits[(c&0x0F) ])) < 0 ) + return rc; + + return(0); +} + +/* ------------------------------------------------------------------------- */ +/* Init an array of 256 entries, mark codes we must escape with value > 0 */ +/* ------------------------------------------------------------------------- */ +static void zsendline_init(char *tab) +{ + int i; + + for( i = 0; i < 256; i++ ) + { + if( i & 0140 ) + tab[i] = 0; + else + { + switch( i ) { + case ZDLE: + case XOFF: /* ^Q */ + case XON: /* ^S */ + case 020: /* ^P */ + case (XOFF | 0200): + case (XON | 0200): + case (020 | 0200): + tab[i] = 1; + break; + case 015: + case (015 | 0200): + if( Z_Ctlesc ) + tab[i] = 1; + else + tab[i] = 2; + break; + default: + if( Z_Ctlesc ) + tab[i] = 1; + else + tab[i] = 0; + } + } /* end of if */ + } /* end of for */ +} + +/* ------------------------------------------------------------------------- */ +/* Decode two lower case hex digits into an 8 bit byte value */ +/* ------------------------------------------------------------------------- */ +static int zgethex(void) +{ + int c, n; + + if( (c = noxrd7()) < 0 ) + return(c); + + n = c - '0'; + if( n > 9 ) n -= ('a' - ':'); + + if( n & ~0xF ) + return(ZERROR); + if( (c = noxrd7()) < 0 ) + return(c); + + c -= '0'; + if( c > 9 ) c -= ('a' - ':'); + if( c & ~0xF ) + return(ZERROR); + + c += (n<<4); + + return(c); +} + +/* ------------------------------------------------------------------------- */ +/* Store long integer pos in hdr */ +/* ------------------------------------------------------------------------- */ +void stohdr(char *hdr, long pos) +{ + hdr[ZP0] = (pos ) & 0377; + hdr[ZP1] = (pos>>8 ) & 0377; + hdr[ZP2] = (pos>>16) & 0377; + hdr[ZP3] = (pos>>24) & 0377; +} + +/* ------------------------------------------------------------------------- */ +/* Recover a long integer from a header */ +/* ------------------------------------------------------------------------- */ +long rclhdr(char *hdr) +{ + register long l; + + l = (hdr[ZP3] & 0377); + l = (l << 8) | (hdr[ZP2] & 0377); + l = (l << 8) | (hdr[ZP1] & 0377); + l = (l << 8) | (hdr[ZP0] & 0377); + return(l); +} diff --git a/source/bforce/prot_zmrecv.c b/source/bforce/prot_zmrecv.c new file mode 100644 index 0000000..645fcfd --- /dev/null +++ b/source/bforce/prot_zmrecv.c @@ -0,0 +1,561 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "session.h" +#include "outbound.h" +#include "io.h" +#include "prot_common.h" +#include "prot_zmodem.h" + +typedef enum zrxstates { + ZRX_INIT, /* Send ZRINIT frame -> goto ZRX_INITACK */ + ZRX_INITACK, /* Wait for answer on ZRINIT (for ZRQINIT?) */ + ZRX_GOTFILE, /* We got ZFINFO -> check it, open, etc.. */ + ZRX_SENDRPOS, /* Send position we want receive file from */ + ZRX_RPOSACK, /* Wait for answer on (ZRPOS) our postion */ + ZRX_WAITDATA, /* And wait for data block with file's data */ + ZRX_REFUSE, /* Feee... Refuse this file */ + ZRX_SKIP /* Burn baby.. burn.. skip it! */ +} e_zrxstates; + +static void zmodem_puts(const char *s); +static int zmodem_proc_ZFILE(s_protinfo *pi, char *blkptr, size_t blklen); + +/* ------------------------------------------------------------------------- */ +/* Receive files with Z-Modem protocol */ +/* Return: */ +/* PRC_SUCCESSFUL: All files received or transfer was finished cleanly */ +/* PRC_ERROR: Error at sending something(include carrier lost) */ +/* PRC_ERROR: Error at receiving something(include carrier lost) */ +/* PRC_MERROR: Misc. errors (i.e. incompatibilies, failures, etc) */ +/* PRC_TRIESOUT: Very many tries doing something without result */ +/* PRC_REMOTEDEAD: For a long time no real information transfered */ +/* PRC_REMOTEABORT: Transfer was aborted by remote (i.e. five CAN, etc..) */ +/* PRC_LOCALBORT: Transfer was aborted by local (i.e. CPS too low, etc..) */ +/* ------------------------------------------------------------------------- */ +int rx_zmodem(s_protinfo *pi, bool caller) +{ + char zconv; /* ZMODEM file conversion request */ + char zmanag; /* ZMODEM file management request */ + char ztrans; /* ZMODEM file transport request */ + char zexten; /* ZMODEM file extended options */ + char *rxbuf; /* Buffer with ZMAXBLOCKLEN size */ + int zrqinitcnt; /* Count received ZRQINITs */ + int zfincnt; /* Count received ZFINs (in state ZTX_INITACK) */ + int inithdrtype; /* Send this header at ZRX_INIT state */ + int txtries = 0; + int skipbypos = 0; + int ftype = 0; + enum zrxstates rxstate; + time_t deadtimer; + int rc = PRC_NOERROR; + int n, c; + + log("start %s receive", Protocols[state.handshake->protocol]); + DEB((D_PROT, "start %s receive", Protocols[state.handshake->protocol])); + + if( pi->start_time == 0 ) + pi->start_time = time(NULL); + + skipbypos = conf_boolean(cf_zmodem_skip_by_pos); + rxbuf = (char *)xmalloc(ZMAXBLOCKLEN+1); + zrqinitcnt = 0; + zfincnt = 0; + inithdrtype = ZRINIT; + Z_Rxwait = ZWAITTIME; + Z_Rxtout = ZRXTIMEOUT; + rxstate = ZRX_INIT; + setalarm(Z_Rxtout); + + timer_set(&deadtimer, ZDEADTIMER); + + while(1) + { + if( timer_expired(deadtimer) ) + { + DEB((D_PROT, "rx_zmodem: deadtimer = %ld", (long)deadtimer)); + DEB((D_PROT, "rx_zmodem: rxstate = %d", (int)rxstate)); + DEB((D_PROT, "rx_zmodem: rc = %d", rc)); + DEB((D_PROT, "rx_zmodem: txtries = %d", txtries)); + + log("brain dead! (abort)"); + + gotoexit(PRC_LOCALABORTED); + } + + if( rxstate == ZRX_INIT || rxstate == ZRX_SENDRPOS ) + { + if( ++txtries > ZMAXTRIES ) + { + log("tries reached miximal count"); + gotoexit(PRC_LOCALABORTED); + } + } + + switch(rxstate) { + case ZRX_INIT: + DEB((D_PROT, "rx_zmodem: entering state ZRX_INIT")); + + stohdr(Z_Txhdr, 0L); + + Z_Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; + + if( Z_Ctlesc ) + Z_Txhdr[ZF0] |= TESCCTL; + + if( zshhdr(inithdrtype, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + + if( inithdrtype == ZSKIP ) + inithdrtype = ZRINIT; + + setalarm(Z_Rxtout); + rxstate = ZRX_INITACK; + break; + + case ZRX_GOTFILE: + DEB((D_PROT, "rx_zmodem: entering state ZRX_GOTFILE")); + + if( pi->recv && pi->recv->fp ) + p_rx_fclose(pi); + + switch(zmodem_proc_ZFILE(pi, rxbuf, Z_Rxcount)) { + case 0: + txtries = 0; + rxstate = ZRX_SENDRPOS; + break; + case 2: + rxstate = ZRX_SKIP; + break; + default: + rxstate = ZRX_REFUSE; + break; + } + break; + + case ZRX_SENDRPOS: + DEB((D_PROT, "rx_zmodem: entering state ZRX_SENDRPOS")); + + stohdr(Z_Txhdr, pi->recv->bytes_received); + + if( zshhdr(ZRPOS, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + + setalarm(Z_Rxtout); + rxstate = ZRX_RPOSACK; + break; + + case ZRX_WAITDATA: + DEB((D_PROT, "rx_zmodem: entering state ZRX_WAITDATA")); + + if( (rc = p_info(pi, 0)) ) + gotoexit(rc); + + setalarm(Z_Rxtout); + + switch(c = zrdata(rxbuf, ZMAXBLOCKLEN, pi->recv->bytes_received)) { + case ZHANGUP: + case ZEXIT: + gotoexit(PRC_ERROR); + break; + case ZCAN: + gotoexit(PRC_REMOTEABORTED); + break; + case ZTIMER: + log("time out waiting for data"); + txtries = 0; + rxstate = ZRX_SENDRPOS; + break; + case ZERROR: + case ZCRCERR: /* CRC error */ + zmodem_puts(Z_Attn); + txtries = 0; + rxstate = ZRX_SENDRPOS; + break; + case GOTCRCW: + case GOTCRCQ: + case GOTCRCG: + case GOTCRCE: + timer_set(&deadtimer, ZDEADTIMER); + + if( (n = p_rx_writefile(rxbuf, Z_Rxcount, pi)) < 0 ) + { + rxstate = ( n == -2 ) ? ZRX_SKIP : ZRX_REFUSE; + break; + } + + pi->recv->bytes_received += Z_Rxcount; + + switch(c) { + case GOTCRCW: + stohdr(Z_Txhdr, pi->recv->bytes_received); + if( zshhdr(ZACK, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); + rxstate = ZRX_RPOSACK; + break; + case GOTCRCQ: + stohdr(Z_Txhdr, pi->recv->bytes_received); + if( zshhdr(ZACK, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); + break; + case GOTCRCG: + break; + case GOTCRCE: + txtries = 0; + rxstate = ZRX_RPOSACK; + break; + } + break; + } + break; + + case ZRX_REFUSE: + DEB((D_PROT, "rx_zmodem: entering state ZRX_REFUSE")); + txtries = 0; + inithdrtype = ZFERR; + rxstate = ZRX_INIT; + break; + + case ZRX_SKIP: + DEB((D_PROT, "rx_zmodem: entering state ZRX_SKIP")); + txtries = 0; + if( skipbypos ) + { + pi->recv->bytes_received = pi->recv->bytes_total; + rxstate = ZRX_SENDRPOS; + } + else + { + inithdrtype = ZSKIP; + rxstate = ZRX_INIT; + } + break; + + default: + break; + } /* end of switch(rxstate) */ + + + if( rxstate != ZRX_INIT && rxstate != ZRX_GOTFILE + && rxstate != ZRX_SENDRPOS && rxstate != ZRX_WAITDATA + && rxstate != ZRX_SKIP && rxstate != ZRX_REFUSE ) + { + switch( ftype = zgethdr(Z_Rxhdr) ) { + case ZCAN: + gotoexit(PRC_REMOTEABORTED); + break; + + case ZHANGUP: + case ZEXIT: + gotoexit(PRC_ERROR); + break; + + case ZTIMER: + log("time out"); + switch(rxstate) { + case ZRX_INITACK: rxstate = ZRX_INIT; break; + case ZRX_RPOSACK: rxstate = ZRX_SENDRPOS; break; + default: break; + } + break; + + case ZERROR: + case ZCRCERR: + /* NAK them all! (TODO: think a little) */ + stohdr(Z_Txhdr, 0L); + + if( zshhdr(ZNAK, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + + break; + + case ZRQINIT: + if( rxstate == ZRX_INITACK ) + { + zrqinitcnt++; + rxstate = ZRX_INIT; + } + break; + + case ZFILE: + if( rxstate == ZRX_INITACK + || rxstate == ZRX_RPOSACK ) + { + zconv = Z_Rxhdr[ZF0]; + zmanag = Z_Rxhdr[ZF1]; + ztrans = Z_Rxhdr[ZF2]; + zexten = Z_Rxhdr[ZF3]; + + /* default to "binary" mode */ + if( !zconv ) + zconv = ZCBIN; + + inithdrtype = ZRINIT; + setalarm(Z_Rxtout); + + switch(zrdata(rxbuf, ZMAXBLOCKLEN, 0)) { + case ZHANGUP: + case ZEXIT: + gotoexit(PRC_ERROR); + break; + case ZTIMER: + txtries = 0; + rxstate = ZRX_INIT; + break; + case GOTCRCW: + rxstate = ZRX_GOTFILE; + break; + default: + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZNAK, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); + rxstate = ZRX_INITACK; + break; + } + } + break; + + case ZSINIT: + if( rxstate == ZRX_INITACK ) + { + Z_Ctlesc = TESCCTL & Z_Rxhdr[ZF0]; + setalarm(Z_Rxtout); + switch( zrdata(Z_Attn, ZATTNLEN, 0) ) { + case ZHANGUP: + case ZEXIT: + gotoexit(PRC_ERROR); + break; + case ZTIMER: + txtries = 0; + rxstate = ZRX_INIT; + break; + case GOTCRCW: + stohdr(Z_Txhdr, 1L); + if( zshhdr(ZACK, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); + rxstate = ZRX_INIT; + break; + default: + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZNAK, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); + break; + } + } + break; + + case ZNAK: + switch(rxstate) { + case ZRX_INITACK: rxstate = ZRX_INIT; break; + case ZRX_RPOSACK: rxstate = ZRX_SENDRPOS; break; + default: break; + } + break; + + case ZEOF: + if( rxstate == ZRX_RPOSACK ) + { + if( rclhdr(Z_Rxhdr) == pi->recv->bytes_received ) + { + pi->recv->status = FSTAT_SUCCESS; + + if( !p_rx_fclose(pi) ) + { + rxstate = ZRX_INIT; + inithdrtype = ZRINIT; + } else + rxstate = ZRX_REFUSE; + + txtries = 0; + } else + log("out of sync"); + } + break; + + case ZSKIP: + if( rxstate == ZRX_RPOSACK ) + { + log("remote side skipped file"); + rxstate = ZRX_INIT; + } + break; + + case ZDATA: + if( rxstate == ZRX_RPOSACK ) + { + if( rclhdr(Z_Rxhdr) == pi->recv->bytes_received ) + { + rxstate = ZRX_WAITDATA; + } + else + { + log("out of sync"); + zmodem_puts(Z_Attn); + txtries = 0; + rxstate = ZRX_SENDRPOS; + } + } + break; + + case ZFREECNT: + if( rxstate == ZRX_INITACK ) + { + stohdr(Z_Txhdr, ~0L); + if( zshhdr(ZACK, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); + } + break; + + case ZCOMMAND: + if( rxstate == ZRX_INITACK ) + { + inithdrtype = ZRINIT; + setalarm(Z_Rxtout); + + switch( zrdata(rxbuf, ZMAXBLOCKLEN, 0) ) { + case ZHANGUP: + case ZEXIT: + gotoexit(PRC_ERROR); + break; + case ZTIMER: + txtries = 0; + rxstate = ZRX_INIT; + break; + case GOTCRCW: + log("remote command execution requested (n/a)"); + log("command: \"%s\"", rxbuf); + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZCOMPL, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); + gotoexit(PRC_LOCALABORTED); + break; + default: + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZNAK, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); + txtries = 0; + rxstate = ZRX_INIT; + break; + } + } + break; + + case ZFIN: + if( zrqinitcnt ) + { + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZFIN, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); + gotoexit(PRC_NOERROR); + } + else if( rxstate == ZRX_INITACK ) + { + /* + * Don't believe first ZFIN on outgoing calls + */ + if( ++zfincnt > ZRXSKIPFIN || !caller ) + { + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZFIN, Z_Txhdr) < 0 ) gotoexit(PRC_ERROR); + gotoexit(PRC_NOERROR); + } + rxstate = ZRX_INIT; + } + break; + + default: + log("got unexpected frame %d", ftype); + break; + } + } + } /* end of while(1) */ + +exit: + DEB((D_PROT, "rx_zmodem: RECV exit = %d", rc)); + + setalarm(0); + + if( pi->recv && pi->recv->fp ) + p_rx_fclose(pi); + + if( rxbuf ) + free(rxbuf); + + return(rc); +} + +/* ------------------------------------------------------------------------- */ +/* Send a string to the modem, processing for \336 (sleep 1 sec) */ +/* and \335 (break signal) */ +/* ------------------------------------------------------------------------- */ +static void zmodem_puts(const char *s) +{ + DEB((D_PROT, "zmodem_puts: \"%s\"", string_printable(s))); + + while( s && *s ) + { + char *p = strpbrk(s, "\335\336"); + + if( !p ) + { + WRITE_TIMEOUT(s, strlen(s)); + return; + } + if( p != s ) + { + WRITE_TIMEOUT(s, p-s); + s = p; + } + + if( *p == '\336' ) + sleep(1); + else + tio_send_break(); + + p++; + } +} + +/* ------------------------------------------------------------------------- */ +/* Process incoming file information header */ +/* ------------------------------------------------------------------------- */ +static int zmodem_proc_ZFILE(s_protinfo *pi, char *blkptr, size_t blklen) +{ + char *fileiptr = NULL; + size_t filesize = 0L; + time_t filetime = 0L; + +#ifdef DEBUG + char *tmp = string_printable_buffer(blkptr, blklen); + + DEB((D_PROT, "zmodem_proc_ZFILE: process \"%s\" (%ld bytes)", + tmp, blklen)); + + if( tmp ) + { + free(tmp); tmp = NULL; + } +#endif + + blkptr[blklen] = '\0'; + + fileiptr = blkptr + strlen(blkptr) + 1; + + if( fileiptr >= (blkptr + blklen) || + sscanf(fileiptr, "%d%lo", &filesize, &filetime) < 1 ) + { + log("zmodem: got invalid ZFILE packet"); + return 1; + } + + DEB((D_PROT, "zmodem_proc_ZFILE: filesize=%ld, filetime=%lo", + (long)filesize, (long)filetime)); + + return p_rx_fopen(pi, blkptr, filesize, filetime, 0); +} + diff --git a/source/bforce/prot_zmsend.c b/source/bforce/prot_zmsend.c new file mode 100644 index 0000000..63b91d2 --- /dev/null +++ b/source/bforce/prot_zmsend.c @@ -0,0 +1,728 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "io.h" +#include "session.h" +#include "prot_common.h" +#include "prot_zmodem.h" + +/* ------------------------------------------------------------------------- */ +/* States of our Zmodem sending protocol */ +/* ------------------------------------------------------------------------- */ +typedef enum ztxstates { + ZTX_START, /* Start sending (init, send "rz\r") */ + ZTX_RQINIT, /* Send ZRQINIT frame */ + ZTX_RQINITACK, /* Wait for answer on ZRQINIT frame */ + ZTX_NEXTFILE, /* Prepare next file for sending */ + ZTX_FINFO, /* Send file's ZFINFO frame with data */ + ZTX_FINFOACK, /* Wait for answer on our ZFINFO + .. */ + ZTX_STARTDATA, /* Start sending of data (send ZDATA?) */ + ZTX_DATA, /* Send new portion of data blocks */ + ZTX_READCHECK, /* Check - we got some chars */ + ZTX_CRCWACK, /* Wait for CRCW ack */ + ZTX_CRCQACK, /* Wait for CRCQ ack */ + ZTX_EOF, /* Send ZEOF frame with our file length */ + ZTX_EOFACK, /* Wait for answer on our ZEOF */ + ZTX_FIN, /* Send ZFIN to finish sending */ + ZTX_FINACK /* Wait for answer on sent ZFIN */ +} e_ztxstates; + +static void zmodem_add_empty_packet(s_protinfo *pi) +{ + struct stat st; + s_filelist **ptrl; + s_packet pkt; + char tmpname[] = "/tmp/bfXXXXXX"; + char *p_tmpname; + + if( (p_tmpname = mktemp(tmpname)) == NULL ) + { + logerr("cannot generate temp. file name for packet from \"%s\"", tmpname); + return; + } + + memset(&pkt, '\0', sizeof(s_packet)); + + pkt.dest = state.node.addr; + pkt.orig = *state.handshake->remote_address(state.handshake); + + if( pkt_createpacket(p_tmpname, &pkt) ) + { + char abuf[BF_MAXADDRSTR+1]; + logerr("cannot create packet for address %s", + ftn_addrstr(abuf, pkt.dest)); + return; + } + + if( stat(p_tmpname, &st) ) + { + logerr("cannot stat created packet \"%s\"", p_tmpname); + unlink(p_tmpname); + return; + } + + for( ptrl = &pi->filelist; *ptrl; ptrl = &((*ptrl)->next) ) + { /* EMPTY LOOP */ } + + (*ptrl) = (s_filelist *)xmalloc(sizeof(s_filelist)); + memset(*ptrl, '\0', sizeof(s_filelist)); + (*ptrl)->fname = xstrcpy(p_tmpname); + (*ptrl)->type = TYPE_NETMAIL; + (*ptrl)->action = ACTION_FORCEUNLINK; + (*ptrl)->size = st.st_size; +} + +/* ------------------------------------------------------------------------- */ +/* Send files with Z-Modem protocol */ +/* Files to transfer stored in pi->syslist structure */ +/* Return: */ +/* PRC_SUCCESSFUL: All files received or transfer was finished cleanly */ +/* PRC_ERROR: Error at sending something(include carrier lost) */ +/* PRC_ERROR: Error at receiving something(include carrier lost) */ +/* PRC_MERROR: Misc. errors (i.e. incompatibilies, failures, etc) */ +/* PRC_TRIESOUT: Very many tries doing something without result */ +/* PRC_REMOTEDEAD: For a long time no real information transfered */ +/* PRC_REMOTEABORT: Transfer was aborted by remote (i.e. five CAN, etc..) */ +/* PRC_LOCALBORT: Transfer was aborted by local (i.e. CPS too low, etc..) */ +/* ------------------------------------------------------------------------- */ +int tx_zmodem(s_protinfo *pi, bool caller) +{ + int startblk = 64; /* Initial Zmodem block size */ + int minblk = 64; /* Minimal Z-protocol block size */ + int maxblk = 1024;/* Maximal Z-protocol block size */ + int blocklen = 0; /* Length of transmitted blocks */ + int goodblk = 0; /* How many blocks we sent w/o ZRPOS'tion :) */ + int txwindow = 0; /* Tranmitter window size (0 means streaming) */ + int newcnt = 0; /* Count free bytes in receiver's buffer */ + int rxbuflen = 0; /* Receiver's max buffer length */ + int rxlastpos = 0; /* Receiver's last reported offset */ + int beenhere = 0; /* How many times we've been ZRPOS'd same place */ + long bytescnt = 0; /* Received bytes(current offset) */ + long lastsync = 0; /* Last offset to which we got a ZRPOS */ + char zconv = 0; /* Local ZMODEM file conversion request */ + char zmanag = 0; /* Local ZMODEM file management request */ + char ztrans = 0; /* Local ZMODEM file translation request */ + char zexten = 0; /* Local ZMODEM file extended options */ + char *txbuf = NULL;/* Buffer with ZMAXBLOCKLEN size */ + int zrinitcnt = 0; /* Count received ZRINITs */ + int rxflags1 = 0; + int rxflags2 = 0; + int txtries = 0; + int junkcnt = 0; + int initacked = 0; /* TRUE when at least one ZRQINIT was sent */ + /* after first ZRINIT was received */ + int rc = 0; /* Our return code */ + int dtype, n; + int ftype; + char c, *p; + long unsigned crc32; + enum ztxstates txstate; + time_t deadtimer; + + log("start %s send", Protocols[state.handshake->protocol]); + DEB((D_PROT, "start %s send", Protocols[state.handshake->protocol])); + + /* Set time transfer started at */ + if( pi->start_time == 0 ) + pi->start_time = time(NULL); + + txbuf = (char *)xmalloc(ZMAXBLOCKLEN+1); + zconv = ZCBIN; + maxblk = (state.handshake->protocol == PROT_ZMODEM) ? 1024 : 8192; + + /* Set initial block size (default is 128b) */ + if( (startblk = conf_number(cf_zmodem_start_block_size)) > 0 ) + { + if( startblk%64 || startblk > maxblk || startblk < 64 ) + startblk = 256; + } else + startblk = 256; + + blocklen = startblk; + txwindow = conf_number(cf_zmodem_tx_window); + Z_Rxwait = ZWAITTIME; + Z_Rxtout = ZRXTIMEOUT; + txstate = ZTX_START; + + timer_set(&deadtimer, ZDEADTIMER); + + setalarm(Z_Rxtout); + + /* + * At zmodem batches send empty netmail packet + * if no real outgoing traffic available + */ + if( !pi->send_left_size && conf_boolean(cf_zmodem_send_dummy_pkt) ) + zmodem_add_empty_packet(pi); + + while(1) + { + if( timer_expired(deadtimer) ) + { + log("brain dead! (abort)"); + gotoexit(PRC_LOCALABORTED); + } + + if( txstate == ZTX_RQINIT || txstate == ZTX_FINFO + || txstate == ZTX_EOF || txstate == ZTX_FIN ) + { +#ifdef DEBUG + if( txtries ) DEB((D_PROT, "tx_zmodem: try #%d", txtries)); +#endif + if( ++txtries > ZMAXTRIES ) + { + log("out of tries"); + gotoexit(PRC_LOCALABORTED); + } + } + + switch(txstate) { + case ZTX_START: + DEB((D_PROT, "tx_zmodem: entering state ZTX_START")); + if( PUTSTR("rz\r") < 0 ) + gotoexit(PRC_ERROR); + txtries = 0; + txstate = ZTX_RQINIT; + break; + + case ZTX_RQINIT: + DEB((D_PROT, "tx_zmodem: entering state ZTX_RQINIT")); + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZRQINIT, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + setalarm(Z_Rxtout); + txstate = ZTX_RQINITACK; + break; + + case ZTX_NEXTFILE: + DEB((D_PROT, "tx_zmodem: entering state ZTX_NEXTFILE")); + if( pi->send && pi->send->fp ) + p_tx_fclose(pi); + txtries = 0; + txstate = p_tx_fopen(pi) ? ZTX_FIN : ZTX_FINFO; + break; + + case ZTX_FINFO: + DEB((D_PROT, "tx_zmodem: entering state ZTX_FINFO")); + + zrinitcnt = 0; + + strnxcpy(txbuf, pi->send->net_name, ZMAXFNAME); + + p = txbuf + strlen(txbuf) + 1; + sprintf(p, "%ld %lo %lo 0 %ld %ld", + (long)pi->send->bytes_total, (long)pi->send->mod_time, + (long)pi->send->mode, (long)pi->send_left_num, + (long)pi->send_left_size); + + DEB((D_PROT, "tx_zmodem: send \"%s\\000%s\"", txbuf, p)); + + Z_Txhdr[ZF0] = zconv; /* file conversion request */ + Z_Txhdr[ZF1] = zmanag; /* file management request */ + Z_Txhdr[ZF2] = ztrans; /* file transport request */ + Z_Txhdr[ZF3] = zexten; + + if( zsbhdr(ZFILE, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + if( zsdata(txbuf, (p - txbuf) + strlen(p), ZCRCW, 0) < 0 ) + gotoexit(PRC_ERROR); + + setalarm(Z_Rxtout); + txstate = ZTX_FINFOACK; + break; + + case ZTX_STARTDATA: + DEB((D_PROT, "tx_zmodem: entering state ZTX_STARTDATA")); + + newcnt = rxbuflen; + junkcnt = 0; + + stohdr(Z_Txhdr, pi->send->bytes_sent); + if( zsbhdr(ZDATA, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + + txstate = ZTX_DATA; + break; + + case ZTX_DATA: + DEB((D_PROT, "tx_zmodem: entering state ZTX_DATA")); + + timer_set(&deadtimer, ZDEADTIMER); + setalarm(Z_Rxtout); /* Remove annoing timeouts! */ + + if( (n = p_tx_readfile(txbuf, blocklen, pi)) < 0 ) + { + /* error occured, remote wait for DATA */ + /* so send null ZCRCE data subpacket */ + if( zsdata(txbuf, 0, ZCRCE, 0) < 0 ) + gotoexit(PRC_ERROR); + txstate = ZTX_NEXTFILE; + break; + } + + if( pi->send->eofseen ) + dtype = ZCRCE; + else if( junkcnt > 6 ) + dtype = ZCRCW; + else if( bytescnt == lastsync ) + dtype = ZCRCW; + else if( rxbuflen && (newcnt -= n) <= 0 ) + dtype = ZCRCW; + else if( txwindow && (bytescnt - rxlastpos + n) >= txwindow ) + dtype = ZCRCQ; + else + dtype = ZCRCG; + + if( (rc = p_info(pi, 0)) ) + gotoexit(rc); + + if( zsdata(txbuf, n, dtype, pi->send->bytes_sent) < 0 ) + gotoexit(PRC_ERROR); + + if( ++goodblk > 5 && blocklen*2 <= maxblk ) + { + goodblk = 0; + blocklen *= 2; + DEB((D_PROT, "tx_zmodem: new blocklen = %ld byte(s)", blocklen)); + } + + bytescnt = pi->send->bytes_sent += n; + + if( dtype == ZCRCW ) + { + junkcnt = 0; + setalarm(Z_Rxtout); + txstate = ZTX_CRCWACK; + break; + } + else if( dtype == ZCRCQ ) + { + junkcnt = 0; + setalarm(Z_Rxtout); + txstate = ZTX_CRCQACK; + break; + } + else if( dtype == ZCRCE ) + { + txtries = 0; + txstate = ZTX_EOF; + break; + } + + if( CHARWAIT(0) ) + { + while( (rc = GETCHAR(1)) != ZTIMER ) + { + if( rc < 0 ) + { + gotoexit(PRC_ERROR); + } + else if( rc == CAN || rc == ZPAD ) + { + DEB((D_PROT, "tx_zmodem: got ZPAD or CAN!")); + setalarm(Z_Rxtout); + txstate = ZTX_READCHECK; + break; + } + else if( rc == XOFF || rc == (XOFF|0200) ) + { + DEB((D_PROT, "tx_zmodem: got XOFF")); + if( GETCHAR(5) < 0 ) + gotoexit(PRC_ERROR); + break; + } + else if( rc == XON || rc == (XON|0200) ) + { + DEB((D_PROT, "tx_zmodem: got XON")); + } + else + { + junkcnt++; + DEB((D_PROT, "tx_zmodem: got JUNK = 0x%x (junkcnt = %d)", + rc, junkcnt)); + } + } /* end of while( rc != ZTIMER ) */ + } /* end of if( CHARWAIT(0) ) */ + break; + + case ZTX_EOF: + DEB((D_PROT, "tx_zmodem: entering state ZTX_EOF")); + + stohdr(Z_Txhdr, pi->send->bytes_sent); + if( zsbhdr(ZEOF, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + + setalarm(Z_Rxtout); + txstate = ZTX_EOFACK; + break; + + case ZTX_FIN: + DEB((D_PROT, "tx_zmodem: entering state ZTX_FIN")); + + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZFIN, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + + setalarm(Z_Rxtout); + txstate = ZTX_FINACK; + break; + + default: + /* Ignore them all */ + break; + } /* end of switch(txstate) */ + + if( txstate != ZTX_START && txstate != ZTX_RQINIT + && txstate != ZTX_FINFO && txstate != ZTX_DATA + && txstate != ZTX_EOF && txstate != ZTX_FIN ) + { + switch( ftype = zgethdr(Z_Rxhdr) ) { + case ZCAN: + gotoexit(PRC_REMOTEABORTED); + break; + + case ZHANGUP: + case ZEXIT: + gotoexit(PRC_ERROR); + break; + + case ZTIMER: + log("time out"); + + if( txstate == ZTX_READCHECK ) + zsdata(txbuf, 0, ZCRCE, 0); + + switch(txstate) { + case ZTX_RQINITACK: txstate = ZTX_RQINIT; break; + case ZTX_FINFOACK: txstate = ZTX_FINFO; break; + case ZTX_READCHECK: txstate = ZTX_STARTDATA; break; + case ZTX_CRCWACK: txstate = ZTX_STARTDATA; break; + case ZTX_CRCQACK: txstate = ZTX_STARTDATA; break; + case ZTX_EOFACK: txstate = ZTX_EOF; break; + case ZTX_FINACK: txstate = ZTX_FIN; break; + default: break; + } + break; + + case ZERROR: + case ZCRCERR: + /* NAK them all! */ + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZNAK, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + break; + + case ZRQINIT: + if( txstate == ZTX_RQINITACK ) + { + if( Z_Rxhdr[0] == ZCOMMAND ) + break; + + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZNAK, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + + txstate = ZTX_RQINIT; + } + else if( txstate == ZTX_FINFOACK ) + { + /* remote is sender - abort */ + log("zmodem: remote is sender"); + gotoexit(PRC_LOCALABORTED); + } + break; + + case ZRINIT: + if( txstate == ZTX_RQINITACK ) + { + if( initacked == 0 ) + { + /* Be sure ack first ZRINIT */ + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZRQINIT, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + initacked = 1; + } + + /* Get receiver's options */ + rxflags1 = (0377 & Z_Rxhdr[ZF0]); + rxflags2 = (0377 & Z_Rxhdr[ZF1]); + Z_Txfcs32 = (rxflags1 & CANFC32); + Z_Ctlesc |= (rxflags1 & TESCCTL); + rxbuflen = (0377 & Z_Rxhdr[ZP0]); + rxbuflen += ((0377 & Z_Rxhdr[ZP1])<<8); + + /* No ZCRCQ if remote doesn't indicate */ + /* FDX ability */ + if( !(rxflags1 & CANFDX) ) + txwindow = 0; + + DEB((D_PROT, "tx_zmodem: Z_Txfcs32 = %d Z_Ctlesc = %d", + Z_Txfcs32, Z_Ctlesc)); + DEB((D_PROT, "tx_zmodem: rxbuflen = %d blocklen = %d", + rxbuflen, blocklen)); + DEB((D_PROT, "tx_zmodem: txwindow = %u", + txwindow)); + + txstate = ZTX_NEXTFILE; + } + else if( txstate == ZTX_FINFOACK ) + { + /* Possible they didn't see */ + /* our file information */ + if( ++zrinitcnt > 2 ) + txstate = ZTX_FINFO; + } + else if( txstate == ZTX_READCHECK + || txstate == ZTX_CRCQACK + || txstate == ZTX_CRCWACK ) + { + if( txstate == ZTX_READCHECK + || txstate == ZTX_CRCQACK ) + zsdata(txbuf, 0, ZCRCE, 0); + + /* Assume file normaly sent ? */ + log("assume file normaly sent"); + + pi->send->status = FSTAT_SUCCESS; + txstate = ZTX_NEXTFILE; + } + else if( txstate == ZTX_EOFACK ) + { + /* ok, send next */ + pi->send->status = FSTAT_SUCCESS; + txstate = ZTX_NEXTFILE; + } + else if( txstate == ZTX_FINACK ) + { + /* Possible we should ignore */ + /* first ZRINIT. Because they */ + /* didn't see our first ZFIN */ + /* But I'm soo lazy .. :)) */ + txstate = ZTX_FIN; + } + break; + + case ZACK: + if( txstate == ZTX_CRCWACK ) + { + rxlastpos = Z_Rxpos; + if( pi->send->bytes_sent == Z_Rxpos ) + txstate = ZTX_STARTDATA; + } + else if( txstate == ZTX_READCHECK + || txstate == ZTX_CRCQACK ) + { + rxlastpos = Z_Rxpos; + txstate = ZTX_DATA; + } + break; + + case ZSKIP: + if( txstate == ZTX_FINFOACK + || txstate == ZTX_READCHECK + || txstate == ZTX_CRCQACK + || txstate == ZTX_CRCWACK + || txstate == ZTX_EOFACK ) + { + if( txstate == ZTX_READCHECK + || txstate == ZTX_CRCQACK ) + zsdata(txbuf, 0, ZCRCE, 0); + + if( txstate == ZTX_READCHECK ) + CLEAROUT(); + + pi->send->status = FSTAT_SKIPPED; + log("remote side skipped file"); + + txstate = ZTX_NEXTFILE; + } + break; + + case ZFIN: + /* BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG! */ + /* BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG! */ + /* BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG!BUG! */ + if( txstate == ZTX_FINACK ) + { + if( PUTSTR("OO") == 0 ) + FLUSHOUT(); + gotoexit(PRC_NOERROR); + } + break; + + case ZRPOS: + if( txstate == ZTX_FINFOACK + || txstate == ZTX_READCHECK + || txstate == ZTX_CRCQACK + || txstate == ZTX_CRCWACK + || txstate == ZTX_EOFACK ) + { + rxlastpos = Z_Rxpos; + + /* Clear modem buffers */ + /* if( txstate != FINFOACK ) SENDBREAK(); */ + if( txstate == ZTX_READCHECK ) CLEAROUT(); + + if( txstate == ZTX_READCHECK + || txstate == ZTX_CRCQACK ) + { + if( zsdata(txbuf, 0, ZCRCE, 0) < 0 ) + gotoexit(PRC_ERROR); + } + + /* Reset EOF flag! */ + pi->send->eofseen = FALSE; + + /* Check pos */ + if( (Z_Rxpos || txstate != ZTX_FINFOACK) + && fseek(pi->send->fp, Z_Rxpos, 0) ) + { + logerr("can't send file from requested position"); + /* Open next file for send */ + txstate = ZTX_NEXTFILE; + break; + } + + if( txstate == ZTX_FINFOACK ) + { + if( Z_Rxpos ) + { + log("resyncing at offset %d", Z_Rxpos); + pi->send->bytes_skipped = Z_Rxpos; + } + } + else if( txstate == ZTX_READCHECK + || txstate == ZTX_CRCWACK + || txstate == ZTX_CRCQACK ) + { + goodblk = 0; + if( lastsync >= Z_Rxpos && ++beenhere > 4 ) + if( blocklen > minblk ) + { + blocklen /= 2; + DEB((D_PROT, "tx_zmodem: falldown to %ld BlockLen", blocklen)); + } + } + + lastsync = bytescnt = pi->send->bytes_sent = Z_Rxpos; + + if( txstate == ZTX_FINFOACK ) + --lastsync; + + txstate = ZTX_STARTDATA; + } + break; + + case ZNAK: + switch(txstate) { + case ZTX_RQINITACK: txstate = ZTX_RQINIT; break; + case ZTX_FINFOACK: txstate = ZTX_FINFO; break; + case ZTX_EOFACK: txstate = ZTX_EOF; break; + case ZTX_FINACK: txstate = ZTX_FIN; break; + default: break; + } + break; + + case ZCRC: + if( txstate == ZTX_FINFOACK ) + { + /* Send file's CRC-32 */ + crc32 = 0xFFFFFFFFL; + + while( ((c = getc(pi->send->fp)) != EOF) && --Z_Rxpos ) + crc32 = updcrc32(c, crc32); + + crc32 = ~crc32; + + clearerr(pi->send->fp); /* Clear EOF */ + fseek(pi->send->fp, 0L, 0); + + stohdr(Z_Txhdr, crc32); + if( zsbhdr(ZCRC, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + } + break; + + case ZCHALLENGE: + if( txstate == ZTX_RQINITACK ) + { + /* Echo receiver's challenge number */ + stohdr(Z_Txhdr, Z_Rxpos); + if( zshhdr(ZACK, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + txstate = ZTX_RQINIT; + } + break; + + case ZCOMMAND: + if( txstate == ZTX_RQINITACK ) + { + txstate = ZTX_RQINIT; + } + break; + + case ZABORT: + log("remote requested for session abort"); + stohdr(Z_Txhdr, 0L); + if( zshhdr(ZFIN, Z_Txhdr) < 0 ) + gotoexit(PRC_ERROR); + gotoexit(PRC_REMOTEABORTED); + break; + + case ZFERR: + if( txstate == ZTX_FINFOACK + || txstate == ZTX_READCHECK + || txstate == ZTX_CRCWACK + || txstate == ZTX_CRCQACK + || txstate == ZTX_EOFACK ) + { + if( txstate == ZTX_READCHECK + || txstate == ZTX_CRCQACK ) + { + if( zsdata(txbuf, 0, ZCRCE, 0) < 0 ) + gotoexit(PRC_ERROR); + } + + pi->send->status = FSTAT_REFUSED; + log("remote side refused file"); + + txstate = ZTX_NEXTFILE; + } + break; + + default: + log("got unexpected frame %d", ftype); + break; + } /* end of switch(hdr) */ + } /* end of if */ + } /* end of while */ + +exit: + DEB((D_PROT, "tx_zmodem: SEND exit = %d", rc)); + + setalarm(0); + + if( pi->send && pi->send->fp ) + p_tx_fclose(pi); + + if( txbuf ) + free(txbuf); + + return(rc); +} + diff --git a/source/bforce/sess_answ.c b/source/bforce/sess_answ.c new file mode 100644 index 0000000..049bff3 --- /dev/null +++ b/source/bforce/sess_answ.c @@ -0,0 +1,138 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" +#include "io.h" +#include "session.h" + +int answ_system(e_session type, char *connstr, int inetd) +{ + TIO oldtio; + struct sockaddr_in client; + int clientlen = sizeof(client); + int rc = 0; + char *p; + + init_state(&state); + state.session = type; + state.caller = FALSE; + state.valid = TRUE; + + /* + * Set verbal line name + */ + if( inetd ) + { + state.linename = xstrcpy("tcpip"); + state.inet = TRUE; + } + else + state.linename = isatty(0) ? port_get_name(ttyname(0)) : NULL; + + if( !inetd ) + { + if( tio_get_dcd(0) == 0 ) + log("warning: DCD line is not active"); + + if( (p = getenv("CALLER_ID")) && *p && strcmp(p, "none") ) + state.cidstr = (char*)xstrcpy(p); + + if( connstr && *connstr ) + state.connstr = (char*)xstrcpy(connstr); + else if( (p = getenv("CONNECT")) && *p ) + state.connstr = (char*)xstrcpy(p); + + if( state.connstr ) + state.connspeed = modem_getconnspeed(state.connstr); + } + + /* + * Open new log file with current line name as extension + */ + if( log_reopen(log_getfilename(LOG_FILE_SESSION), state.linename, NULL) ) + { + log("can't continue without logging"); + gotoexit(BFERR_FATALERROR); + } + +#ifdef DEBUG + (void)debug_setfilename(log_getfilename(LOG_FILE_DEBUG)); +#endif + + if( inetd ) + { + if( connstr && *connstr ) + state.connstr = (char*)xstrcpy(connstr); + else if( getpeername(0, (struct sockaddr*)&client, &clientlen) == -1 ) + logerr("can't get client address"); + else + { + state.peername = (char*)xstrcpy(inet_ntoa(client.sin_addr)); + state.peerport = (long)ntohs(client.sin_port); + } + } + + if( inetd == 0 && state.cidstr ) + { + setproctitle("bforce answering, CID: %.32s", + string_printable(state.cidstr)); + log("Caller-ID: \"%s\"", + string_printable(state.cidstr)); + } + else if( inetd && state.peername ) + { + setproctitle("bforce answering, host %.32s:%ld", + string_printable(state.peername), state.peerport); + log("TCP/IP connect from %s on port %ld", + string_printable(state.peername), state.peerport); + } + else + { + setproctitle("bforce answering"); + } + + if( state.connstr ) + log("connect \"%s\" (%ld)", state.connstr, state.connspeed); + + if( (inetd == 0 && (rc = port_init(0, 0, &oldtio, FALSE)) == 0) + || (inetd == 1 && (rc = tcpip_init()) == 0) ) + { + port_carrier(0, TRUE); + + rc = session(); + + if( !inetd ) + { + port_deinit(0, &oldtio); + port_close(); + } + } + else + rc = BFERR_FATALERROR; + +exit: + out_bsy_unlockall(); + + log("session rc = %d (\"%s\")", rc, BFERR_NAME(rc)); + + if( state.node.addr.zone > 0 ) + (void)session_stat_update(&state.node.addr, + &state.sess_stat, FALSE, rc); + + deinit_state(&state); + return(rc); +} diff --git a/source/bforce/sess_call.c b/source/bforce/sess_call.c new file mode 100644 index 0000000..de71c5d --- /dev/null +++ b/source/bforce/sess_call.c @@ -0,0 +1,716 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" +#include "io.h" +#include "session.h" + +#ifdef XXXX +/* Unused */ +int call_system_modem_init(TIO *old_tio_settings) +{ + int rc = BFERR_NOERROR; + char abuf[BF_MAXADDRSTR+1]; + int c; + TIO oldtio; /* Original terminal settings */ + long minspeed = 0L; /* Min connect speed */ + long waittime = 0L; /* Abort dialing after.. */ + char dialstring[256] = ""; /* Modem dial string with phone number */ + char phone[BFORCE_MAX_PHONE+1]; + const char *p_resetstr = NULL; /* Modem reset string */ + const char *p_prefstr = NULL; /* Modem dial prefix string */ + const char *p_suffstr = NULL; /* Modem dial suffix string */ + + /* + * Set verbal line name to the modem device name + */ + state.linename = port_get_name(state.modemport->name); + + /* + * Open new log file with current line name as extension + */ + if( log_reopen(log_getfilename(LOG_FILE_SESSION), + state.linename, NULL) ) + { + log("can't continue without logging"); + return BFERR_FATALERROR; + } + +#ifdef DEBUG + (void)debug_setfilename(log_getfilename(LOG_FILE_DEBUG)); +#endif + + if( (rc = port_open(state.modemport, 1, old_tio_setting)) ) + { + log("cannot open modem port \"%s\"", + state.modemport->name); + return BFERR_PORTBUSY; + } + + /* Load dialing options */ + p_resetstr = conf_string(cf_modem_reset_command); + p_prefstr = conf_string(cf_modem_dial_prefix); + p_suffstr = conf_string(cf_modem_dial_suffix); + waittime = conf_number(cf_wait_carrier_out); + + /* Set default wait for carrier time */ + if( !waittime ) + waittime = 120; + + /* Prepare dial string */ + *dialstring = '\0'; + if( p_prefstr ) + strnxcpy(dialstring, p_prefstr, sizeof(dialstring)); + else + log("warning: no modem dial prefix defined"); + + modem_transphone(phone, state.node.phone, sizeof(phone)); + strnxcat(dialstring, phone, sizeof(phone)); + + if( p_suffstr ) + strnxcat(dialstring, p_suffstr, sizeof(dialstring)); + else + log("warning: no modem dial suffix defined"); + + log("calling %s (%s, %s)", + ftn_addrstr(abuf, state.node.addr), + (state.node.name && *state.node.name) ? state.node.name : "", + string_printable(dialstring)); + + /* Clear modem buffer from possible "NO CARRIER"s */ + CLEARIN(); + + /* Reset modem */ + if( p_resetstr && *p_resetstr ) + { + if( (c = modem_command(p_resetstr, 5, TRUE)) ) + { + log("can't reset modem: %s", modem_errlist[c]); + port_deinit(0, &oldtio); + port_close(); + return BFERR_NOMODEM; /* XXX close port? */ + } + /* Try to remove some needless + * modem responses from buffer */ + CLEARIN(); + } + + rc = modem_dial(dialstring, waittime, &state.connstr); + + if( rc ) + { + /* Error must be allready reported */ + port_deinit(0, &oldtio); + port_close(); + return BFERR_CANT_CONNECT10; + } + + if( state.connstr ) + { + state.connspeed = modem_getconnspeed(state.connstr); + log("connect \"%s\" (%ld)", + state.connstr, state.connspeed); + } + + minspeed = conf_number(cf_min_speed_out); + if( state.connspeed && state.connspeed < minspeed ) + { + TTYRESET(); + log("connect speed too low, at least %ld required", + minspeed); + port_deinit(0, &oldtio); + port_close(); + return BFERR_CONNECT_TOOLOW; + } + + /* Give modem some time for raising DCD line */ + usleep(100000); /* 0.1 sec */ + + if( tio_get_dcd(0) == 0 ) + log("warning: DCD line is not active after connect!"); + + port_carrier(0, TRUE); + + return BFERR_NOERROR; +} + +/* Unused */ +int call_system_modem_deinit(TIO *old_tio_settings) +{ + const char *p_hangstr; /* Modem hangup string */ + const char *p_statstr; /* Modem statistic string */ + + p_hangstr = conf_string(cf_modem_hangup_command); + p_statstr = conf_string(cf_modem_stat_command); + + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + + CLEARIN(); CLEAROUT(); + + /* Hangup if we think modem is still online! */ + if( !tty_hangup && p_hangstr && *p_hangstr ) + { + TTYRESET(); /* Reset error flags */ + + if( (c = modem_hangup(p_hangstr, 5)) ) + log("can't hangup modem: %s", modem_errlist[c]); + } + + /* Write modem statistic to log file */ + if( p_statstr && *p_statstr ) + { + TTYRESET(); /* Reset error flags */ + + if( (c = modem_command(p_statstr, 10, TRUE)) ) + log("can't get modem statistic: %s", modem_errlist[c]); + } + + port_deinit(0, old_tio_settings); + port_close(); + + return BFERR_NOERROR; +} +#endif /* XXXX */ + +int call_system_quiet(const char *connstr, bool inet) +{ + TIO oldtio; + struct sockaddr_in client; + int clientlen = sizeof(client); + int rc = 0; + char *p; + + /* + * Set verbal line name + */ + if( inet ) { + state.linename = xstrcpy("tcpip"); + state.inet = TRUE; + } + else + state.linename = isatty(0) ? port_get_name(ttyname(0)) : NULL; + + if( !inet ) + { + if( tio_get_dcd(0) == 0 ) + log("warning: DCD line is not active"); + + if( connstr && *connstr ) + state.connstr = (char*)xstrcpy(connstr); + else if( (p = getenv("CONNECT")) && *p ) + state.connstr = (char*)xstrcpy(p); + + if( state.connstr ) + state.connspeed = modem_getconnspeed(state.connstr); + } + + /* + * Open new log file with current line name as extension + */ + if( log_reopen(log_getfilename(LOG_FILE_SESSION), state.linename, NULL) ) + { + log("can't continue without logging"); + return BFERR_FATALERROR; + } + +#ifdef DEBUG + (void)debug_setfilename(log_getfilename(LOG_FILE_DEBUG)); +#endif + + if( inet ) + { + if( connstr && *connstr ) + state.connstr = (char*)xstrcpy(connstr); + else if( getpeername(0, (struct sockaddr*)&client, &clientlen) == -1 ) + logerr("can't get client address"); + else + { + state.peername = (char*)xstrcpy(inet_ntoa(client.sin_addr)); + state.peerport = (long)ntohs(client.sin_port); + } + } + + if( !inet && state.cidstr ) + { + setproctitle("bforce outgoing, CID: %.32s", + string_printable(state.cidstr)); + log("Caller-ID: \"%s\"", + string_printable(state.cidstr)); + } + else if( inet && state.peername ) + { + setproctitle("bforce outgoing, host %.32s:%ld", + string_printable(state.peername), state.peerport); + log("TCP/IP connect from %s on port %ld", + string_printable(state.peername), state.peerport); + } + else + { + setproctitle("bforce outgoing"); + } + + if( state.connstr ) + log("connect \"%s\" (%ld)", state.connstr, state.connspeed); + + if( (!inet && (rc = port_init(0, 0, &oldtio, FALSE)) == 0) + || ( inet && (rc = tcpip_init()) == 0) ) + { + port_carrier(0, TRUE); + + rc = session(); + + if( !inet ) + { + port_deinit(0, &oldtio); + port_close(); + } + } + else + rc = BFERR_FATALERROR; + + return rc; +} + +/* ------------------------------------------------------------------------- */ +/* Before using we must lock tty and set: */ +/* state.node - node information */ +/* state.modemport - to modem device we are going to use */ +/* ------------------------------------------------------------------------- */ +int call_system_modem(void) +{ + char abuf[BF_MAXADDRSTR+1]; + int c, rc = BFERR_NOERROR; + TIO oldtio; /* Original terminal settings */ + long minspeed = 0L; /* Min connect speed */ + long waittime = 0L; /* Abort dialing after.. */ + char dialstring[256] = ""; /* Modem dial string with phone number */ + char phone[BFORCE_MAX_PHONE+1]; + const char *p_resetstr = NULL; /* Modem reset string */ + const char *p_prefstr = NULL; /* Modem dial prefix string */ + const char *p_suffstr = NULL; /* Modem dial suffix string */ + const char *p_hangstr = NULL; /* Modem hangup string */ + const char *p_statstr = NULL; /* Modem statistic string */ + + /* + * Set verbal line name to the modem device name + */ + state.linename = port_get_name(state.modemport->name); + + /* + * Open new log file with current line name as extension + */ + if( log_reopen(log_getfilename(LOG_FILE_SESSION), + state.linename, NULL) ) + { + log("can't continue without logging"); + return BFERR_FATALERROR; + } + +#ifdef DEBUG + (void)debug_setfilename(log_getfilename(LOG_FILE_DEBUG)); +#endif + + if( (rc = port_open(state.modemport, 1, &oldtio)) == 0 ) + { + /* Load dialing options */ + p_resetstr = conf_string(cf_modem_reset_command); + p_prefstr = conf_string(cf_modem_dial_prefix); + p_suffstr = conf_string(cf_modem_dial_suffix); + p_hangstr = conf_string(cf_modem_hangup_command); + p_statstr = conf_string(cf_modem_stat_command); + waittime = conf_number(cf_wait_carrier_out); + + /* Set default wait for carrier time */ + if( !waittime ) + waittime = 120; + + *dialstring = '\0'; + + if( p_prefstr ) + strnxcpy(dialstring, p_prefstr, sizeof(dialstring)); + else + log("warning: no modem dial prefix defined"); + + modem_transphone(phone, state.node.phone, sizeof(phone)); + strnxcat(dialstring, phone, sizeof(phone)); + + if( p_suffstr ) + strnxcat(dialstring, p_suffstr, sizeof(dialstring)); + else + log("warning: no modem dial suffix defined"); + + log("calling %s (%s, %s)", + ftn_addrstr(abuf, state.node.addr), + (state.node.name && *state.node.name) ? state.node.name : "", + string_printable(dialstring)); + + /* + * Clear modem buffer from possible "NO CARRIER"s + */ + CLEARIN(); + + /* + * Reset modem + */ + if( p_resetstr && *p_resetstr ) + { + if( (c = modem_command(p_resetstr, 5, TRUE)) ) + { + log("can't reset modem: %s", modem_errlist[c]); + return BFERR_NOMODEM; /* XXX close port */ + } + /* + * Try to remove some needless + * modem responses from buffer + */ + CLEARIN(); + } + + rc = modem_dial(dialstring, waittime, &state.connstr); + + if( rc < 0 ) + { + rc = BFERR_CANT_CONNECT10; + } + else if( rc == 0 ) + { + if( state.connstr ) + { + state.connspeed = modem_getconnspeed(state.connstr); + log("connect \"%s\" (%ld)", state.connstr, state.connspeed); + } + + minspeed = conf_number(cf_min_speed_out); + + if( state.connspeed && state.connspeed < minspeed ) + { + TTYRESET(); + log("connect speed too low, at least %ld required", minspeed); + rc = BFERR_CONNECT_TOOLOW; + } + else + { + /* Give modem some time for rising DCD line */ + usleep(100000); /* 0.1 sec */ + + if( tio_get_dcd(0) == 0 ) + log("warning: DCD line is not active after connect!"); + + port_carrier(0, TRUE); + + rc = session(); + + port_carrier(0, FALSE); + } + + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + + CLEARIN(); CLEAROUT(); + + /* Hangup if we think modem is still online! */ + if( !tty_hangup && p_hangstr && *p_hangstr ) + { + TTYRESET(); /* Reset error flags */ + + if( (c = modem_hangup(p_hangstr, 5)) ) + log("can't hangup modem: %s", modem_errlist[c]); + } + + /* Write modem statistic to log file */ + if( p_statstr && *p_statstr ) + { + TTYRESET(); /* Reset error flags */ + + if( (c = modem_command(p_statstr, 10, TRUE)) ) + log("can't get modem statistic: %s", modem_errlist[c]); + } + } + port_deinit(0, &oldtio); + port_close(); + } + else + { + log("cannot open modem port \"%s\"", state.modemport->name); + rc = BFERR_PORTBUSY; + } + + return rc; +} + +int call_system_tcpip(void) +{ + char abuf[BF_MAXADDRSTR+1]; + int rc = BFERR_NOERROR; + + /* + * Set verbal line name to "tcpip" value + */ + state.linename = xstrcpy("tcpip"); + + state.inet = TRUE; + + /* + * Open new log file with current line name as extension + */ + if( log_reopen(log_getfilename(LOG_FILE_SESSION), + state.linename, NULL) ) + { + log("can't continue without logging"); + return BFERR_FATALERROR; + } + +#ifdef DEBUG + (void)debug_setfilename(log_getfilename(LOG_FILE_DEBUG)); +#endif + + if( nodelist_checkflag(state.node.flags, "BINKP") == 0 + || nodelist_checkflag(state.node.flags, "IBN") == 0 ) + { + state.tcpmode = TCPMODE_BINKP; + state.session = SESSION_BINKP; + } + else if( nodelist_checkflag(state.node.flags, "TELN") == 0 ) + { + state.tcpmode = TCPMODE_TELNET; + state.session = SESSION_UNKNOWN; + } + else if( nodelist_checkflag(state.node.flags, "IFC") == 0 ) + { + state.tcpmode = TCPMODE_RAW; + state.session = SESSION_UNKNOWN; + } + else /* Default is "raw" mode */ + { + state.tcpmode = TCPMODE_RAW; + state.session = SESSION_UNKNOWN; + } + + log("calling %s (%s, %s)", + ftn_addrstr(abuf, state.node.addr), + (state.node.name && *state.node.name ) ? state.node.name : "", + (state.node.phone && *state.node.phone) ? state.node.phone : ""); + + if( (rc = tcpip_connect(state.node.phone, state.tcpmode)) == 0 + && (rc = tcpip_init() == 0) ) + { + TTYSTATUS(1); + rc = session(); + tcpip_shutdown(); + } + else + { + rc = BFERR_CANT_CONNECT10; + } + + return rc; +} + +int call_system(s_faddr addr, const s_bforce_opts *opts) +{ + int rc = 0; + char abuf[BF_MAXADDRSTR+1]; + char *p_lockdir = NULL; + char *errmsg = NULL; + bool inet = FALSE; + + init_state(&state); + + state.caller = TRUE; + state.valid = TRUE; + state.node.addr = addr; + nodelist_lookup(&state.node, addr); + state.listed = state.node.listed; + state.node.addr.domain[0] = '\0'; /* Discard domain for node address */ + + if( opts->dontcall ) + goto do_session; + + /* + * Get node overrides + */ + if( override_get(&state.override, state.node.addr, opts->hiddline) ) + { + errmsg = "incorrect hidden line number"; + gotoexit(BFERR_PHONE_UNKNOWN); + } + + /* + * Apply overrides to the node information + */ + if( state.override.sFlags ) + { + strnxcat(state.node.flags, ",", sizeof(state.node.flags)); + strnxcat(state.node.flags, state.override.sFlags, sizeof(state.node.flags)); + } + + if( opts->iaddr && *opts->iaddr ) + { + inet = TRUE; + (void)strnxcpy(state.node.phone, + opts->iaddr, sizeof(state.node.phone)); + } + else if( opts->phone && *opts->phone ) + { + (void)strnxcpy(state.node.phone, + opts->phone, sizeof(state.node.phone)); + } + else if( state.override.sIpaddr ) + { + inet = TRUE; + (void)strnxcpy(state.node.phone, + state.override.sIpaddr, sizeof(state.node.phone)); + } + else if( state.override.sPhone ) + { + (void)strnxcpy(state.node.phone, + state.override.sPhone, sizeof(state.node.phone)); + } + + if( !inet ) + { + if( !modem_isgood_phone(state.node.phone) ) + errmsg = "don't know phone number"; + } + else + { + if( !tcpip_isgood_host(state.node.phone) ) + errmsg = "don't know host name"; + } + + if( errmsg ) + gotoexit(BFERR_PHONE_UNKNOWN); + + /* + * Is now a working time for that node/line + */ + if( !inet && !opts->force) + { + time_t unixtime = time(NULL); + struct tm *now = localtime(&unixtime); + bool goodtime; + + if( !opts->hiddline ) + { + if( state.override.sFlags && !nodelist_checkflag(state.override.sFlags, "CM") ) + goodtime = TRUE; + else + { + if( timevec_isdefined(&state.override.worktime) ) + goodtime = timevec_isnow(&state.override.worktime, now); + else + { + if( !nodelist_checkflag(state.node.flags, "CM") ) + goodtime = TRUE; + else + goodtime = timevec_isnow(&state.node.worktime, now); + } + } + } + else + goodtime = timevec_isnow(&state.override.worktime, now); + + if( !goodtime ) + { + errmsg = "not works now, try later"; + gotoexit(BFERR_NOTWORKING); + } + } + +do_session: + /* + * It's easier to ignore than handle! After connect + * new handlers must be installed, don't worry. + */ + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + + /* + * Try to lock address of system we are going to call + */ +#ifdef BFORCE_USE_CSY + if( out_bsy_lock(state.node.addr, TRUE) ) +#else + if( out_bsy_lock(state.node.addr) ) +#endif + { + errmsg = "cannot lock address"; + gotoexit(BFERR_SYSTEM_LOCKED); + } + + setproctitle("bforce calling %.32s, %.32s", + ftn_addrstr(abuf, state.node.addr), state.node.phone); + + if( opts->dontcall ) + { + rc = call_system_quiet(opts->connect, opts->inetd); + } + else if( !inet ) + { + if( (p_lockdir = conf_string(cf_uucp_lock_directory)) == NULL ) + p_lockdir = BFORCE_LOCK_DIR; + + if( opts->device && *opts->device ) + { + if( (state.modemport = + modem_getmatch_port(opts->device)) == NULL ) + { + errmsg = "unknown port name"; + gotoexit(BFERR_PORTBUSY); + } + } + else if( (state.modemport = + modem_getfree_port(p_lockdir)) == NULL ) + { + errmsg = "no free matching ports"; + gotoexit(BFERR_PORTBUSY); + } + + if( port_lock(p_lockdir, state.modemport) ) + { + errmsg = "cannot lock modem port"; + gotoexit(BFERR_PORTBUSY); + } + else /* Successfuly locked port */ + { + rc = call_system_modem(); + port_unlock(p_lockdir, state.modemport); + } + } + else + { + rc = call_system_tcpip(); + } + +exit: + out_bsy_unlockall(); + + if( errmsg ) + log("call to %s failed: %s", ftn_addrstr(abuf, addr), errmsg); + + log("session rc = %d (\"%s\")", rc, BFERR_NAME(rc)); + + (void)session_stat_update(&state.node.addr, + &state.sess_stat, TRUE, rc); + + deinit_state(&state); + return(rc); +} diff --git a/source/bforce/sess_common.c b/source/bforce/sess_common.c new file mode 100644 index 0000000..028f617 --- /dev/null +++ b/source/bforce/sess_common.c @@ -0,0 +1,187 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" +#include "session.h" + +/* + * Environment variables: + * $REM_ADDR_FTN, + * $REM_ADDR_INET, + * $LOC_ADDR_FTN, + * $LOC_ADDR_INET, + * $PASSWORD, + * $MAILER, + * $LOCATION, + * $SYSOP, + * $SYSTEM_NAME + * $PHONE, + * $FLAGS + * $PROTECTED, + * $LISTED, + * $INBOUND + * $CONNECT, + * $CALLERID, + * $RC + */ +int session_run_command(const char *execstr) +{ + int rc = 0; + s_faddr *addr; + char abuf[BF_MAXADDRSTR+1]; + char sbuf[32]; + s_exec_options eopts; + char *p; + + exec_options_init(&eopts); + + if( state.handshake ) + { + if( state.handshake->remote_address + && (addr = state.handshake->remote_address(state.handshake)) ) + { + exec_env_add(&eopts, "REM_ADDR_FTN", + ftn_addrstr_fido(abuf, *addr)); + exec_env_add(&eopts, "REM_ADDR_INET", + ftn_addrstr_inet(abuf, *addr)); + } + + if( state.handshake->local_address + && (addr = state.handshake->local_address(state.handshake)) ) + { + exec_env_add(&eopts, "LOC_ADDR_FTN", + ftn_addrstr_fido(abuf, *addr)); + exec_env_add(&eopts, "LOC_ADDR_INET", + ftn_addrstr_inet(abuf, *addr)); + } + + if( state.handshake->remote_password + && (p = state.handshake->remote_password(state.handshake)) ) + exec_env_add(&eopts, "PASSWORD", p); + + if( state.handshake->remote_mailer + && (p = state.handshake->remote_mailer(state.handshake)) ) + exec_env_add(&eopts, "MAILER", p); + + if( state.handshake->remote_location + && (p = state.handshake->remote_location(state.handshake)) ) + exec_env_add(&eopts, "LOCATION", p); + + if( state.handshake->remote_sysop_name + && (p = state.handshake->remote_sysop_name(state.handshake)) ) + exec_env_add(&eopts, "SYSOP", p); + + if( state.handshake->remote_system_name + && (p = state.handshake->remote_system_name(state.handshake)) ) + exec_env_add(&eopts, "SYSTEM_NAME", p); + + if( state.handshake->remote_phone + && (p = state.handshake->remote_phone(state.handshake)) ) + exec_env_add(&eopts, "PHONE", p); + + if( state.handshake->remote_flags + && (p = state.handshake->remote_flags(state.handshake)) ) + exec_env_add(&eopts, "FLAGS", p); + } + + if( state.valid ) + { + exec_env_add(&eopts, "PROTECTED", state.protected ? "1" : "0"); + exec_env_add(&eopts, "LISTED", state.listed ? "1" : "0"); + + if( state.inbound && *state.inbound ) + exec_env_add(&eopts, "INBOUND", state.inbound); + + if( state.connstr && *state.connstr ) + exec_env_add(&eopts, "CONNECT", state.connstr); + + if( state.cidstr && *state.cidstr ) + exec_env_add(&eopts, "CALLERID", state.cidstr); + + if( state.session_rc >= 0 ) + { + sprintf(sbuf, "%d", state.session_rc); + exec_env_add(&eopts, "RC", sbuf); + } + } + + exec_options_set_command(&eopts, execstr); + + rc = exec_command(&eopts); + + exec_options_deinit(&eopts); + + return rc; +} + +int override_get(s_override *dest, s_faddr addr, int line) +{ + s_override *p; + int curline = 0; + + p = conf_override(cf_override, addr); + + curline = 0; + while( p && curline < line ) + { + p = p->hidden; + ++curline; + } + + if( p && curline == line ) + { + *dest = *p; + return 0; + } + else if( line == 0 ) + return 0; + else + return 1; +} + +void init_state(s_state *pstate) +{ + memset(pstate, '\0', sizeof(s_state)); + pstate->session_rc = -1; +} + +void deinit_state(s_state *pstate) +{ + if( pstate->linename ) + free(pstate->linename); + if( pstate->cidstr ) + free(pstate->cidstr); + if( pstate->peername ) + free(pstate->peername); + if( pstate->connstr ) + free(pstate->connstr); + if( pstate->inbound ) + free(pstate->inbound); + if( pstate->tinbound ) + free(pstate->tinbound); + if( pstate->mailfor ) + deinit_falist(pstate->mailfor); + + deinit_fsqueue(&pstate->queue); + + if( state.handshake && state.handshake->deinit ) + state.handshake->deinit(state.handshake); + + memset(pstate, '\0', sizeof(s_state)); + + pstate->session_rc = -1; +} diff --git a/source/bforce/sess_init.c b/source/bforce/sess_init.c new file mode 100644 index 0000000..1a99185 --- /dev/null +++ b/source/bforce/sess_init.c @@ -0,0 +1,507 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "version.h" +#include "logger.h" +#include "util.h" +#include "io.h" +#include "session.h" + +#define INTRO_MAX_SIZE 512 +#define INTRO_MAX_LINES 10 +#define OUTGOING_MAST_TIMER 60 +#define OUTGOING_SYNC_TIMER 5 +#define INCOMING_MAST_TIMER 60 +#define INCOMING_SYNC_TIMER 2 + +/* ------------------------------------------------------------------------- */ +/* Initiate outbound session and define handshake protocol */ +/* On success: zero (state.session is handshake type) */ +/* On error: non-zero (state.session set to UNKNOWN) */ +/* ------------------------------------------------------------------------- */ +int session_init_outgoing(void) +{ + int c = 0; + int tries = 0; + int pos_emsi = 0; + int pos_intro = 0; + bool canemsi = FALSE; + bool canyoohoo = FALSE; + bool canftsc = FALSE; + bool canintro = FALSE; + char buf_emsi[13]; + char buf_intro[256]; + int emsi_seq = 0; /* start reading emsi sequence */ + int enqcount = 0; /* number of ENQ received */ + int nakcount = 0; /* number of NAK or 'C' received */ + int enq_need = 1; + int nak_need = 1; + time_t mast_timer = 0; /* master timer, seems to be 60sec */ + time_t sync_timer = 0; /* resync every .. seconds */ + long options = conf_options(cf_options); + int intro_lines = 0; + int intro_count = 0; + int unexp_count = 0; + + state.session = SESSION_UNKNOWN; + + if( (options & OPTIONS_NO_EMSI) != OPTIONS_NO_EMSI ) + canemsi = TRUE; + if( (options & OPTIONS_NO_YOOHOO) != OPTIONS_NO_YOOHOO ) + canyoohoo = TRUE; + if( (options & OPTIONS_NO_FTS1) != OPTIONS_NO_FTS1 ) + canftsc = TRUE; + if( (options & OPTIONS_NO_INTRO) != OPTIONS_NO_INTRO ) + canintro = TRUE; + + enq_need = canemsi ? 2 : 1; + nak_need = (canemsi || canyoohoo) ? 2 : 1; + + /* + * Put CR until any character received + */ + if( PUTCHAR('\r') < 0 || FLUSHOUT() < 0 ) + return 1; + + while( !CHARWAIT(1) ) + { + if( ++tries > 15 ) + { + log("too much tries waking remote"); + return 1; + } + + if( PUTCHAR('\r') < 0 || FLUSHOUT() < 0 ) + return 1; + } + +#ifdef DEBUG + if( tries > 0 ) + DEB((D_HSHAKE, "tx_init: remote waked on %d try", tries)); +#endif + + /* + * Safety is the 1st law + */ + *buf_emsi = '\0'; + *buf_intro = '\0'; + + /* + * Start timers + */ + timer_set(&mast_timer, OUTGOING_MAST_TIMER); + timer_set(&sync_timer, OUTGOING_SYNC_TIMER*2); + + /* + * Determine supported handshakes on called system + * (support for FTS-1, YooHoo, EMSI) + */ + while(1) + { + if( timer_expired(mast_timer) ) + { + log("session initialisation timed out"); + DEB((D_HSHAKE, "handshake initialisation timed out")); + + return 1; + } + + if( timer_expired(sync_timer) ) + { + DEB((D_HSHAKE, "tx_sendsync: resyncing")); + + if( canemsi && PUTSTR("**EMSI_INQC816**EMSI_INQC816") < 0 ) + return 1; + if( canyoohoo && PUTCHAR(YOOHOO) < 0 ) + return 1; + if( canftsc && PUTCHAR(TSYNC) < 0 ) + return 1; + if( canemsi && PUTCHAR('\r') < 0 ) + return 1; + + if( FLUSHOUT() < 0 ) + return 1; + + timer_set(&sync_timer, OUTGOING_SYNC_TIMER); + } + + /* + * Pickup next char + */ + c = GETCHAR(1); + + if( canintro && c > 0 ) + { + if( c == XON || c == XOFF ) + { + /* Do nothing. Drop them down */ + } + else if( c == '\r' || c == '\n' ) + { + if( pos_intro > 0 ) + { + intro_lines += 1; + intro_count += pos_intro; + + recode_intro_in(buf_intro); + log("intro: \"%s\"", + string_printable(buf_intro)); + + pos_intro = 0; + buf_intro[0] = '\0'; + } + } + else if( pos_intro < sizeof(buf_intro) - 1 ) + { + buf_intro[pos_intro++] = (char)c; + buf_intro[pos_intro ] = '\0'; + } + + if( pos_intro >= sizeof(buf_intro) - 1 ) + { + intro_lines += 1; + intro_count += pos_intro; + + recode_intro_in(buf_intro); + log("intro buffer is full"); + log("intro: \"%s\"", + string_printable(buf_intro)); + + pos_intro = 0; + buf_intro[0] = '\0'; + } + + if( intro_lines >= INTRO_MAX_LINES ) + { + log("stop logging intro: %d lines limit", intro_lines); + canintro = FALSE; + } + else if( intro_count >= INTRO_MAX_SIZE ) + { + log("stop logging intro: %d bytes limit", intro_count); + canintro = FALSE; + } + } + + if( c < 0 ) + { + if( c != TTY_TIMEOUT ) + { + DEB((D_HSHAKE, "tx_init: got TTY_ERROR/TTY_HANGUP")); + return 1; + } + } + else if( c == XON || c == XOFF ) + { + /* Do nothing. Drop them down */ + } + else if( c == ENQ ) + { + if( enq_need && ++enqcount >= enq_need && canyoohoo ) + { + DEB((D_HSHAKE, "tx_init: exit with YooHoo")); + state.session = SESSION_YOOHOO; + return 0; + } + } + else if( c == TSYNC ) + { + if( nak_need && ++nakcount > nak_need && canftsc ) + { + DEB((D_HSHAKE, "tx_init: exit with FTS-1")); + state.session = SESSION_FTSC; + return 0; + } + } + else if( canemsi && c > ' ' && c < '~' ) + { + if( c != 'C' ) + nakcount = 0; + + enqcount = 0; + + if( c == '*' ) + { + memset(buf_emsi, '\0', sizeof(buf_emsi)); + pos_emsi = 0; + emsi_seq = 1; + } + else if( emsi_seq ) + { + if( pos_emsi < sizeof(buf_emsi)-1 ) + { + buf_emsi[pos_emsi++] = (char)c; + buf_emsi[pos_emsi ] = '\0'; + } + + if( pos_emsi >= sizeof(buf_emsi)-1 ) + { + emsi_seq = 0; + + DEB((D_HSHAKE, "tx_init: emsi buffer full \"%s\"", + string_printable(buf_emsi))); + + if( !strncasecmp(buf_emsi, "EMSI_REQA77E", 12) + || !strncasecmp(buf_emsi, "EMSI_NAKEEC3", 12) ) + { + DEB((D_HSHAKE, "tx_init: exit with EMSI")); + state.session = SESSION_EMSI; + + if( PUTSTR("**EMSI_INQC816\r") < 0 + || PUTSTR("**EMSI_INQC816\r") < 0 ) + return 1; + if( FLUSHOUT() < 0 ) + return 1; + + return 0; + } + else if( !strncasecmp(buf_emsi, "EMSI_INQC816", 12) ) + { + /* + * Most probable it is echo of + * our own EMSI_INQ, try to send + * separated EMSI_INQ as user + * name and password to be sure + * that they understand us. + */ + + /* Wait for a login prompt */ + sleep(3); + + if( PUTSTR("**EMSI_INQC816\r") < 0 + || FLUSHOUT() < 0 ) + return 1; + + /* Wait for a password prompt */ + sleep(2); + + if( PUTSTR("**EMSI_INQC816\r") < 0 + || FLUSHOUT() < 0 ) + return 1; + + timer_set(&sync_timer, OUTGOING_SYNC_TIMER); + } + else if( !strncasecmp(buf_emsi, "EMSI", 4) ) + { + log("unexpected emsi sequence \"%s\"", + string_printable(buf_emsi)); + + if( ++unexp_count > 10 ) + { + log("too many unexpected emsi sequences"); + return 1; + } + } + } + } + } + else if( emsi_seq ) + { + emsi_seq = 0; + DEB((D_HSHAKE, "sm_rx_waitseq: bad character 0x%02x in \"%s\"", + c, string_printable(buf_emsi))); + } + } + + return 1; +} + +/* ------------------------------------------------------------------------- */ +/* Initiate inbound session and define handshake protocol */ +/* On success: return zero (state.session defines handshake type) */ +/* On error: return non-zero (state.session set to HSHAKE_UNKNOWN) */ +/* */ +/* TODO: It is not working yet, it only reports about EMSI requests.. (1) */ +/* ------------------------------------------------------------------------- */ +int session_init_incoming(void) +{ + int c = 0; + int pos = 0; + bool canemsi = FALSE; + bool canyoohoo = FALSE; + bool canftsc = FALSE; + char buf[13]; + int emsi_seq = 0; /* start reading emsi sequence */ + int yoohoo_count = 0; /* number of ENQ received */ + int tsync_count = 0; /* number of NAK or 'C' received */ + int yoohoo_need = 1; + int tsync_need = 1; + time_t mast_timer = 0; /* master timer, seems to be 60sec */ + time_t sync_timer = 0; + long options = conf_options(cf_options); + int unexp_count = 0; + + state.session = SESSION_UNKNOWN; + + if( (options & OPTIONS_NO_EMSI) != OPTIONS_NO_EMSI ) + canemsi = TRUE; + if( (options & OPTIONS_NO_YOOHOO) != OPTIONS_NO_YOOHOO ) + canyoohoo = TRUE; + if( (options & OPTIONS_NO_FTS1) != OPTIONS_NO_FTS1 ) + canftsc = TRUE; + + yoohoo_need = canemsi ? 2 : 1; + tsync_need = (canemsi || canyoohoo) ? 2 : 1; + + if( PUTCHAR('\r') < 0 ) + return 1; + + /* + * Output banner + */ + if( canemsi && PUTSTR("**EMSI_REQA77E\r") < 0 ) + return 1; + + if( state.connstr ) + { + /* Show connect string */ + if( PUTCHAR('[') < 0 ) + return 1; + if( PUTSTR(state.connstr) < 0 ) + return 1; + if( PUTSTR("]\n") < 0 ) + return 1; + } + + if( PUTSTR(BF_BANNERVER) < 0 || PUTCHAR(' ') < 0 + || PUTSTR(BF_COPYRIGHT) < 0 || PUTCHAR('\n') < 0 ) + return 1; + + if( FLUSHOUT() < 0 ) + return 1; + + /* Start timers */ + timer_set(&mast_timer, INCOMING_MAST_TIMER); + timer_set(&sync_timer, INCOMING_SYNC_TIMER/2); + + /* + * Determine supported handshakes on called system + * (support for FTS-1, YooHoo, EMSI) + */ + while(1) + { + if( timer_expired(mast_timer) ) + { + log("session initialisation timed out"); + DEB((D_HSHAKE, "handshake initialisation timed out")); + + return 1; + } + + if( timer_expired(sync_timer) ) + { + DEB((D_HSHAKE, "rx_init: resyncing")); + + if( canemsi && PUTSTR("**EMSI_REQA77E\r") < 0 ) + return 1; + + if( FLUSHOUT() < 0 ) + return 1; + + timer_set(&sync_timer, INCOMING_SYNC_TIMER); + } + + /* + * Pickup next char + */ + if( (c = GETCHAR(1)) < 0 ) + { + if( c != TTY_TIMEOUT ) + { + DEB((D_HSHAKE, "rx_init: got TTY_ERROR/TTY_HANGUP")); + return 1; + } + } + else if( c == XON || c == XOFF ) + { + /* Do nothing. Drop them down */ + } + else if( c == YOOHOO ) + { + if( ++yoohoo_count >= yoohoo_need && canyoohoo ) + { + DEB((D_HSHAKE, "rx_init: exit with YooHoo")); + state.session = SESSION_YOOHOO; + + return 0; + } + } + else if( c == TSYNC ) + { + if( ++tsync_count > tsync_need && canftsc ) + { + DEB((D_HSHAKE, "rx_init: exit with FTS-1")); + state.session = SESSION_FTSC; + + return 0; + } + } + else if( canemsi && c > ' ' && c < '~' ) + { + tsync_count = 0; + yoohoo_count = 0; + + if( c == '*' ) + { + memset(buf, '\0', sizeof(buf)); + pos = 0; + emsi_seq = 1; + } + else if( emsi_seq ) + { + if( pos < sizeof(buf)-1 ) + { + buf[pos++] = (char)(c & 0xff); + buf[pos ] = '\0'; + } + + if( pos >= sizeof(buf)-1 ) + { + emsi_seq = 0; + + DEB((D_HSHAKE, "rx_init: emsi buffer full \"%s\"", + string_printable(buf))); + + if( !strncasecmp(buf, "EMSI_INQC816", 12) ) + { + DEB((D_HSHAKE, "rx_init: exit with EMSI")); + state.session = SESSION_EMSI; + + return 0; + } + else if( !strncasecmp(buf, "EMSI", 4) ) + { + log("unexpected emsi sequence \"%s\"", + string_printable(buf)); + + if( ++unexp_count > 10 ) + { + log("too many unexpected emsi sequences"); + return 1; + } + } + } + } + } + else if( emsi_seq ) + { + emsi_seq = 0; + DEB((D_HSHAKE, "rx_init: bad character 0x%02x in \"%s\"", + c, string_printable(buf))); + } + } + + return 1; +} diff --git a/source/bforce/sess_main.c b/source/bforce/sess_main.c new file mode 100644 index 0000000..d351fce --- /dev/null +++ b/source/bforce/sess_main.c @@ -0,0 +1,872 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "bforce.h" +#include "util.h" +#include "nodelist.h" +#include "session.h" +#include "prot_zmodem.h" +#include "prot_yoohoo.h" +#include "prot_emsi.h" +#include "prot_binkp.h" + +/* All session information stores here */ +s_state state; + +int hydra(s_protinfo *pi, bool flag_RH1); + +s_faddr *session_get_bestaka(s_faddr addr) +{ + s_cval_entry *addr_ptr; + s_cval_entry *hide_ptr; + s_faddr *best = NULL; + int bestl = 0; + int curl = 0; + + for( addr_ptr = conf_first(cf_address); addr_ptr; + addr_ptr = conf_next(addr_ptr) ) + { + for( hide_ptr = conf_first(cf_hide_our_aka); hide_ptr; + hide_ptr = conf_next(hide_ptr) ) + { + if( !ftn_addrcomp(hide_ptr->d.falist.addr, addr_ptr->d.falist.addr) ) + break; + } + + if( !hide_ptr ) + { + curl = ftn_addrsmetric(addr_ptr->d.falist.addr, addr); + + if( curl > bestl || best == NULL ) + { + bestl = curl; + best = &addr_ptr->d.falist.addr; + } + } + } + + return best; +} + +int session_addrs_lock(s_sysaddr *addrs, int anum) +{ + int i; + char abuf[BF_MAXADDRSTR+1]; + bool one_lock = FALSE; + + for( i = 0; i < anum; i++ ) + { + if( addrs[i].good ) + { +#ifdef BFORCE_USE_CSY + if( out_bsy_lock(addrs[i].addr, FALSE) ) +#else + if( out_bsy_lock(addrs[i].addr) ) +#endif + { + log("exclude address %s: allready locked", + ftn_addrstr(abuf, addrs[i].addr)); + addrs[i].busy = TRUE; + } + else + one_lock = TRUE; + } + } + + return one_lock ? 0 : -1; +} + +int session_addrs_add(s_sysaddr **addrs, int *anum, s_faddr addr) +{ + int i; + char abuf[BF_MAXADDRSTR+1]; + + if( *anum && *addrs ) + { + /* Check for addresses duplication */ + for( i = 0; i < *anum; i++ ) + { + if( !ftn_addrcomp((*addrs)[i].addr, addr) ) + { + log("exclude address %s: duplicated address", + ftn_addrstr(abuf, addr)); + return -1; + } + } + } + + if( *addrs && *anum ) + *addrs = xrealloc(*addrs, sizeof(s_sysaddr)*(*anum+1)); + else + *addrs = xmalloc(sizeof(s_sysaddr)); + + memset(&(*addrs)[*anum], '\0', sizeof(s_sysaddr)); + + (*addrs)[*anum].addr = addr; + (*addrs)[*anum].busy = FALSE; + (*addrs)[*anum].good = FALSE; + + ++(*anum); + + return 0; +} + +int session_addrs_check(s_sysaddr *addrs, int anum, const char *passwd, + const char *challenge, int challenge_length) +{ + int i; + char abuf[BF_MAXADDRSTR+1]; + char pbuf[32]; + bool failure = FALSE; + bool success = FALSE; + bool cram = (challenge && *challenge); + + if( !anum ) + return -1; + + for( i = 0; i < anum; i++ ) + { + if( session_check_addr(addrs[i].addr) ) + { + log("exclude address %s: not acceptable", + ftn_addrstr(abuf, addrs[i].addr)); + continue; + } + + if( !session_get_password(addrs[i].addr, pbuf, sizeof(pbuf)) ) + { + bool good_passwd = FALSE; + + if( passwd && *passwd ) + { + if( cram ) + { + char digest_bin[16]; + char digest_hex[33]; + + md5_cram_get(pbuf, challenge, challenge_length, digest_bin); + + /* Encode digest to the hex string */ + string_bin_to_hex(digest_hex, digest_bin, 16); + + if( strcasecmp(passwd, digest_hex) == 0 ) + good_passwd = TRUE; + } + else if( strcasecmp(passwd, pbuf) == 0 ) + good_passwd = TRUE; + } + + if( good_passwd ) + { + /* correct password */ + addrs[i].good = TRUE; + state.protected = TRUE; + success = TRUE; + } + else + { + log("exclude address %s: bad password", + ftn_addrstr(abuf, addrs[i].addr)); + addrs[i].good = FALSE; + failure = TRUE; + } + } + else + /* not password protected address */ + addrs[i].good = TRUE; + } + + /* + * Return error, if received password is incorrect for all AKAs + */ + if( failure && !success ) + return -1; + + return 0; +} + +int session_addrs_to_falist(s_sysaddr *addrs, int anum, s_falist **dest) +{ + int i; + + for( i = 0; i < anum; i++ ) + { + if( !addrs[i].busy && addrs[i].good ) + { + (*dest) = (s_falist *)xmalloc(sizeof(s_falist)); + memset(*dest, '\0', sizeof(s_falist)); + (*dest)->addr = addrs[i].addr; + dest = (s_falist**)&((*dest)->next); + } + } + + return 0; +} + +int session_addrs_check_genuine(s_sysaddr *addrs, int anum, s_faddr expected) +{ + int i; + + for( i = 0; i < anum; i++ ) + { + if( !ftn_addrcomp(addrs[i].addr, expected) ) + return 0; + } + + return 1; +} + +/* ------------------------------------------------------------------------- */ +/* Return non-zero value if current speed too low */ +/* ------------------------------------------------------------------------- */ +int session_check_speed(void) +{ + state.minspeed = conf_number(cf_min_speed_in); + + if( state.connspeed > 0 && state.minspeed > state.connspeed ) + return 1; + + return 0; +} + +int session_check_addr(s_faddr addr) +{ + s_cval_entry *addr_ptr; + + for( addr_ptr = conf_first(cf_address); addr_ptr; + addr_ptr = conf_next(addr_ptr) ) + { + if( !ftn_addrcomp(addr, addr_ptr->d.falist.addr) ) + return 1; + } + + return 0; +} + +/* ------------------------------------------------------------------------- */ +/* Get session password for address $addr, put it in $buf */ +/* If no password found - return non-zero value */ +/* ------------------------------------------------------------------------- */ +int session_get_password(s_faddr addr, char *buffer, size_t buflen) +{ + s_cval_entry *pwd_ptr; + + for( pwd_ptr = conf_first(cf_password); pwd_ptr; + pwd_ptr = conf_next(pwd_ptr) ) + { + if( !ftn_addrcomp(addr, pwd_ptr->d.falist.addr) ) + { + strnxcpy(buffer, pwd_ptr->d.falist.what, buflen); + return 0; + } + } + + return 1; +} + +int session_remote_lookup(s_sysaddr *addrs, int anum) +{ + int i; + + for( i = 0; i < anum; i++ ) + { + if( addrs[i].good ) + { + nodelist_lookup(&state.node, addrs[i].addr); + state.node.addr.domain[0] = '\0'; + state.listed = state.node.listed; + break; + } + } + + return (i < anum) ? 0 : -1; +} + +void session_remote_log_status(void) +{ + log("remote is %s,%s", + (state.listed) ? "listed" : "unlisted", + (state.protected) ? "protected" : "unprotected"); +} + +/* ------------------------------------------------------------------------- */ +/* Set inbound directory, create temporary inbound in it, check permissions */ +/* If something wrong - return non-zero value */ +/* ------------------------------------------------------------------------- */ +int session_set_inbound(void) +{ + struct stat st; + char *p_inb; + + if( (p_inb = conf_string(cf_inbound_directory)) ) + { + state.inbound = (char*)xstrcpy(p_inb); + } + else + { + log("no inbound specified, assume \"./\""); + state.inbound = (char*)xstrcpy("./"); + } + + state.tinbound = (char*)xstrcpy(state.inbound); + state.tinbound = (char*)xstrcat(state.tinbound, "tmp/"); + + /* + * Warning, access() make checks using real uid and gid + * (not effective), so we can fail, but.. + */ + if( stat(state.tinbound, &st) == 0 ) + { + if( (st.st_mode & S_IFDIR) != S_IFDIR ) + { + log("temporary inbound \"%s\" is not directory", state.tinbound); + return(1); + } + else if( access(state.tinbound, R_OK|W_OK|X_OK) ) + { + log("have no r/w permission to temporary inbound \"%s\"", state.tinbound); + return(1); + } + } + else if( errno == ENOENT ) + { + /* "tmp" inbound doesn't exist */ + if( mkdir(state.tinbound, 0700) < 0 ) + { + logerr("can't create temporary inbound \"%s\"", state.tinbound); + return(1); + } + chmod(state.tinbound, 0700); + } + else + { + /* Different stat() errors */ + logerr("can't stat temporary inbound \"%s\"", state.tinbound); + return 1; + } + + return(0); +} + +/* ------------------------------------------------------------------------- */ +/* Set status of _OUR_ FREQ processor */ +/* ------------------------------------------------------------------------- */ +void session_set_freqs_status(void) +{ + int root_ok = 0; + int magc_ok = 0; + char *p; + long options; + + state.reqstat = REQS_DISABLED; + + options = conf_options(cf_options); + + if( (options & OPTIONS_MAILONLY) == OPTIONS_MAILONLY + || (options & OPTIONS_NO_FREQS) == OPTIONS_NO_FREQS ) + { state.reqstat = REQS_NOTALLOW; return; } + + if( state.connspeed > 0 + && state.connspeed < conf_number(cf_freq_min_speed) ) + { state.reqstat = REQS_NOTALLOW; return; } + + if( (p = conf_string(cf_freq_srif_command)) && *p ) + { + /* + * Can we execute this processor? Disable freqs if we can't! + */ + if( !exec_file_exist(p) ) + state.reqstat = REQS_ALLOW; + else + logerr("can't stat SRIF processor \"%s\"", p); + } + else + { + /* Check root dir */ + if( (p = conf_string(cf_freq_dir_list)) && *p ) + { + if( access(p, R_OK) == 0 ) + root_ok = 1; + else + logerr("can't stat FREQ dir list \"%s\"", p); + } + + /* Check magic dir */ + if( (p = conf_string(cf_freq_alias_list)) && *p ) + { + if( access(p, R_OK) == 0 ) + magc_ok = 1; + else + logerr("can't stat FREQ alias list \"%s\"", p); + } + + /* Set FREQ processor status */ + if( root_ok || magc_ok ) + state.reqstat = REQS_ALLOW; + } +} + +/* ------------------------------------------------------------------------- */ +/* Set our "send options" (common part, based on our local settings) */ +/* ------------------------------------------------------------------------- */ +void session_set_send_options(void) +{ + const long options = conf_options(cf_options); + + if( state.caller == FALSE ) + state.sopts.holdreq = 1; + + if( (options & OPTIONS_MAILONLY) == OPTIONS_MAILONLY ) + state.sopts.holdxt = 1; + if( (options & OPTIONS_HOLDXT) == OPTIONS_HOLDXT ) + state.sopts.holdxt = 1; + if( (options & OPTIONS_HOLDREQ) == OPTIONS_HOLDREQ ) + state.sopts.holdreq = 1; + if( (options & OPTIONS_HOLDALL) == OPTIONS_HOLDALL ) + state.sopts.holdall = 1; + if( (options & OPTIONS_HOLDHOLD) == OPTIONS_HOLDHOLD ) + state.sopts.holdhold = 1; +} + +/* ------------------------------------------------------------------------- */ +/* Return (non-zero) if we _CAN'T_ send this file NOW! */ +/* ------------------------------------------------------------------------- */ +static int holdfile(s_filelist *fi, const char *delayout) +{ + if( state.sopts.holdall ) return(1); + if( state.sopts.holdxt && !(fi->type & TYPE_NETMAIL) ) return(1); + if( state.sopts.holdreq && (fi->type & TYPE_REQUEST) ) return(1); + if( state.sopts.holdhold && fi->flavor == FLAVOR_HOLD ) return(1); + if( fi->status != STATUS_WILLSEND ) return(1); + if( delayout && !checkmasks(delayout, fi->fname) ) return(2); + + return 0; +} + +/* ------------------------------------------------------------------------- */ +/* Set SKIP flag for files we can't send NOW */ +/* ------------------------------------------------------------------------- */ +void session_set_send_files(void) +{ + int holdmsg = 0, rc = 0; + s_filelist *ptrl = NULL; + + const char *delayout = conf_string(cf_delay_files_send); + + for( ptrl = state.queue.fslist; ptrl; ptrl = ptrl->next ) + if( (rc = holdfile(ptrl, delayout)) ) + { + if( rc == 2 && !holdmsg ) + { + log("delaying files \"%s\"", delayout); + ++holdmsg; + } + ptrl->status = STATUS_SKIP; + } +} + +int session_create_files_queue(s_sysaddr *addrs, int anum) +{ + s_falist *mailfor = NULL; + s_outbound_callback_data ocb; + + /* Set addresses for which we will send files */ + (void)session_addrs_to_falist(addrs, anum, &mailfor); + + /* Scan outbound directory */ + if( mailfor ) + { + memset(&ocb, '\0', sizeof(s_outbound_callback_data)); + ocb.callback = out_handle_fsqueue; + ocb.dest = (void *)&state.queue; + (void)out_scan(&ocb, mailfor); + (void)session_set_send_files(); + (void)session_traffic_set_outgoing(&state.traff_send); + } + + return 0; +} + +int session_traffic_set_incoming(s_traffic *dest) +{ + memset(dest, '\0', sizeof(s_traffic)); + + if( state.handshake && state.handshake->remote_traffic ) + return state.handshake->remote_traffic(state.handshake, dest); + + return -1; +} + +int session_traffic_set_outgoing(s_traffic *dest) +{ + s_filelist *ptrl; + + memset(dest, '\0', sizeof(s_traffic)); + + for( ptrl = state.queue.fslist; ptrl; ptrl = ptrl->next ) + { + if( ptrl->type & TYPE_NETMAIL ) + { + dest->netmail_size += ptrl->size; + dest->netmail_num++; + } + else if( ptrl->type & TYPE_ARCMAIL ) + { + dest->arcmail_size += ptrl->size; + dest->arcmail_num++; + } + else + { + dest->files_size += ptrl->size; + dest->files_num++; + } + } + + return 0; +} + +void session_traffic_log(bool incoming, s_traffic *traff) +{ + char buf[32]; + char msg[128] = ""; + + if( traff == NULL ) + strcpy(msg, "unknown"); + else if( traff->netmail_size == 0 + && traff->arcmail_size == 0 && traff->files_size == 0 ) + strcpy(msg, "none"); + else + { + if( traff->netmail_size > 0 ) + { + string_humansize(buf, traff->netmail_size); + strcat(msg, buf); + strcat(msg, " netmail, "); + } + if( traff->arcmail_size > 0 ) + { + string_humansize(buf, traff->arcmail_size); + strcat(msg, buf); + strcat(msg, " arcmail, "); + } + if( traff->files_size > 0 ) + { + string_humansize(buf, traff->files_size); + strcat(msg, buf); + strcat(msg, " files, "); + } + if( *msg ) + msg[strlen(msg)-2] = '\0'; + } + + log("%s traffic: %s", incoming ? "incoming" : "outgoing", msg); +} + +void session_traffic(void) +{ + int rc; + + rc = session_traffic_set_incoming(&state.traff_recv); + session_traffic_log(TRUE, rc ? NULL : &state.traff_recv); + + /* Outgoing traffic must be allread calculated */ + session_traffic_log(FALSE, &state.traff_send); +} + +/* + * History file line format: + * line verbal name, + * remote address, + * session start time (Unix), + * session_length (seconds), + * session status flags (L - listed, P - protected), + * session result code (one of mailer return codes), + * size of sent netmail, + * size of sent arcmail, + * size of sent files, + * size of received netmail, + * size of received arcmail, + * size of received files + */ +void session_update_history(s_traffic *send, s_traffic *recv, int rc) +{ + FILE *hist_fp; + char *hist_file = conf_string(cf_history_file); + char abuf[BFORCE_MAX_ADDRSTR+1]; + char session_status[32] = ""; + + if( !hist_file ) + return; + + hist_fp = file_open(hist_file, "a"); + if( !hist_fp ) + { + logerr("cannot open history file \"%s\"", hist_file); + return; + } + + + if( state.listed ) + strcat(session_status, "L"); + if( state.protected ) + strcat(session_status, "P"); + if( state.caller ) + strcat(session_status, "O"); + else + strcat(session_status, "I"); + + fprintf(hist_fp, "%s,%s,%lu,%u,%s,%d,%lu,%lu,%lu,%lu,%lu,%lu\n", + state.linename ? state.linename : "", + state.node.addr.zone ? ftn_addrstr(abuf, state.node.addr) : "", + (unsigned long) state.start_time, + (unsigned int) time_elapsed(state.start_time), + session_status, + rc, + (unsigned long) send->netmail_size, + (unsigned long) send->arcmail_size, + (unsigned long) (send->files_size + send->freqed_size), + (unsigned long) recv->netmail_size, + (unsigned long) recv->arcmail_size, + (unsigned long) (recv->files_size + recv->freqed_size)); + + + (void)file_close(hist_fp); +} + +/* ------------------------------------------------------------------------- */ +/* Start session with another FTN mailer */ +/* ------------------------------------------------------------------------- */ +int session(void) +{ + s_protinfo pi; + int rc = BFERR_NOERROR; + s_traffic traff_send; + s_traffic traff_recv; + char *p; + + memset(&traff_send, '\0', sizeof(s_traffic)); + memset(&traff_recv, '\0', sizeof(s_traffic)); + + /* Store session start time */ + state.start_time = time(NULL); + + if( state.session == SESSION_UNKNOWN ) + { + rc = state.caller ? session_init_outgoing() + : session_init_incoming(); + + if( rc ) + gotoexit(BFERR_HANDSHAKE_ERROR); + } + + /* -------------------------------------------------------------- */ + /* Handshake part */ + /* -------------------------------------------------------------- */ + switch( state.session ) { + case SESSION_EMSI: + state.handshake = &handshake_protocol_emsi; + break; + case SESSION_BINKP: + state.handshake = &handshake_protocol_binkp; + break; + case SESSION_YOOHOO: + state.handshake = &handshake_protocol_yoohoo; + break; + case SESSION_FTSC: + log("%sbound FTS-1 session", state.caller?"out":"in"); + log("FTS-1 session not availabe"); + gotoexit(BFERR_HANDSHAKE_ERROR); + case SESSION_UNKNOWN: + ASSERT_MSG(); + gotoexit(BFERR_HANDSHAKE_ERROR); + default: + ASSERT_MSG(); + gotoexit(BFERR_HANDSHAKE_ERROR); + } + + state.handshake->init(state.handshake); + + log("%sbound %s session", + state.caller ? "out" : "in", state.handshake->verbal_name); + + rc = state.caller ? state.handshake->outgoing_session(state.handshake) + : state.handshake->incoming_session(state.handshake); + + DEB((D_PROT, "session: handshake rc = %d", rc)); + + if( rc != HRC_OK ) + { + const char *errmsg = NULL; + + switch(rc) { + case HRC_LOW_SPEED: + errmsg = "connect speed too low"; + rc = BFERR_CONNECT_TOOLOW; + break; + case HRC_BAD_PASSWD: + errmsg = "security violation"; + rc = BFERR_HANDSHAKE_ERROR; + break; + case HRC_NO_ADDRESS: + errmsg = "no expected address was presented"; + rc = BFERR_HANDSHAKE_ERROR; + break; + case HRC_NO_PROTOS: + errmsg = "no common protocols"; + rc = BFERR_HANDSHAKE_ERROR; + break; + case HRC_BUSY: + errmsg = "all remote addresses are busy"; + rc = BFERR_HANDSHAKE_ERROR; + break; + case HRC_FATAL_ERR: + case HRC_TEMP_ERR: + case HRC_OTHER_ERR: + errmsg = NULL; + rc = BFERR_HANDSHAKE_ERROR; + break; + default: + errmsg = "unexpected error number"; + rc = BFERR_HANDSHAKE_ERROR; + break; + } + + if( errmsg ) + log("abort session due to: %s", errmsg); + } + else + { + /* + * Execute 'run_after_handshake' command + */ + if( (p = conf_string(cf_run_after_handshake)) ) + session_run_command(p); + + /* + * Files transfer part + */ + DEB((D_FREQ, "setreqstat: Our FREQ processor status: \"%s\"", + ( state.reqstat == REQS_ALLOW ) ? "Allowed": + ( state.reqstat == REQS_NOTALLOW ) ? "Not allowed now": + ( state.reqstat == REQS_DISABLED ) ? "No FREQs available":"Error")); + DEB((D_HSHAKE, "session: decided to use %s protocol", + Protocols[state.handshake->protocol])); + + /* + * Log expected traffic + */ + session_traffic(); + + init_protinfo(&pi, state.caller); + + switch(state.handshake->protocol) { + case PROT_BINKP: + rc = binkp_transfer(&pi); + break; + case PROT_ZMODEM: + case PROT_ZEDZAP: + case PROT_DIRZAP: + rc = state.caller ? tx_zmodem(&pi, state.caller) + : rx_zmodem(&pi, state.caller); + if( rc == PRC_NOERROR ) + { + rc = state.caller ? rx_zmodem(&pi, state.caller) + : tx_zmodem(&pi, state.caller); + } + break; + case PROT_JANUS: + log("Janus is not available in current version"); + break; + case PROT_HYDRA: + rc = hydra(&pi, state.sopts.hydraRH1); + break; + case PROT_NOPROT: + log("no common protocols available"); + break; + default: + ASSERT_MSG(); + break; + } + + /* + * Convert value returned by protocol to the BForce return code + */ + switch(rc) { + case PRC_NOERROR: rc = BFERR_NOERROR; break; + case PRC_ERROR: + case PRC_REMOTEABORTED: + case PRC_LOCALABORTED: rc = BFERR_XMITERROR; break; + case PRC_CPSTOOLOW: rc = BFERR_CPSTOOLOW; break; + case PRC_STOPTIME: rc = BFERR_STOPTIME; break; + default: ASSERT_MSG(); + } + state.session_rc = rc; + + /* + * Do session clenup (remove temp. files, etc.) + */ + (void)p_session_cleanup(&pi, (rc == BFERR_NOERROR)); + + if( rc == BFERR_NOERROR ) + { + /* + * Flush our 'stdout' buffer + */ + FLUSHOUT(); + + /* + * Remove empty .?lo files + */ + (void)out_flo_unlinkempty(state.queue.flotab, state.queue.flonum); + + /* + * Wait a little if we are answering on incoming call + * (to be sure that all data will be sent) (?) + */ + if( !state.caller ) sleep(1); + } + + /* + * Remove all .bsy locks + */ + out_bsy_unlockall(); + + /* + * Write total amount of received/sent bytes, files, etc. + */ + p_log_txrxstat(&pi); + + /* + * Save session traffic before deiniting + */ + traff_send = pi.traffic_sent; + traff_recv = pi.traffic_rcvd; + + deinit_protinfo(&pi); + + /* + * Execute 'run_after_session' command + */ + if( (p = conf_string(cf_run_after_session)) ) + session_run_command(p); + } + +exit: + state.session_rc = rc; + session_update_history(&traff_send, &traff_recv, rc); + + return rc; +} diff --git a/source/bforce/sess_stat.c b/source/bforce/sess_stat.c new file mode 100644 index 0000000..77e5ca3 --- /dev/null +++ b/source/bforce/sess_stat.c @@ -0,0 +1,304 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "bforce.h" +#include "util.h" +#include "nodelist.h" +#include "session.h" + +/* + * Format of 'sts' files (project only..) + * + * Header: + * 0 byte - version (current is 1) + * 1 byte - global undialable flag (for all lines) + * 2 word - tries + * 4 word - handshake tries + * 6 dword - hold all calls until + * 8 dword - node will not accept our file requests till this time + * 10 dword - last successfull outgoing session + * 12 dword - last successfull incoming session + * + * Each entry (per-line statistics) + */ + +void session_stat_reset_counters(s_sess_stat *stat) +{ + stat->tries = TRIES_RESET; + stat->tries_noansw = TRIES_RESET; + stat->tries_noconn = TRIES_RESET; + stat->tries_nodial = TRIES_RESET; + stat->tries_hshake = TRIES_RESET; + stat->tries_sessns = TRIES_RESET; +} + +static char *session_stat_get_stsfile(s_faddr *addr, int linenum) +{ + char buf[32]; + char *yield = NULL; + char *p_stsdir = conf_string(cf_status_directory); + + if( p_stsdir && *p_stsdir ) + { + if( linenum == -1 ) + sprintf(buf, "%u.%u.%u.%u.sts", + addr->zone, addr->net, + addr->node, addr->point); + else + sprintf(buf, "%u.%u.%u.%u-%u.sts", + addr->zone, addr->net, + addr->node, addr->point, linenum); + + yield = string_concat(p_stsdir, buf, NULL); + } + + return yield; +} + +static int session_stat_read_stsfile(FILE *fp, s_sess_stat *stat) +{ + if( fseek(fp, 0, SEEK_SET) == -1 ) + return -1; + + memset(stat, '\0', sizeof(s_sess_stat)); + + fscanf(fp, "%u %u %u %u %u %u %lu %lu %lu %lu", + (unsigned int *) &stat->tries, + (unsigned int *) &stat->tries_noconn, + (unsigned int *) &stat->tries_noansw, + (unsigned int *) &stat->tries_nodial, + (unsigned int *) &stat->tries_hshake, + (unsigned int *) &stat->tries_sessns, + (unsigned long *) &stat->hold_until, + (unsigned long *) &stat->hold_freqs, + (unsigned long *) &stat->last_success_out, + (unsigned long *) &stat->last_success_in); + + /* Set last successfull session time */ + stat->last_success = MAX(stat->last_success_out, stat->last_success_in); + + return 0; +} + +static int session_stat_write_stsfile(FILE *fp, s_sess_stat *stat) +{ + if( fseek(fp, 0, SEEK_SET) == -1 ) + return -1; + + fprintf(fp, "%u %u %u %u %u %u %lu %lu %lu %lu", + (unsigned int) stat->tries, + (unsigned int) stat->tries_noconn, + (unsigned int) stat->tries_noansw, + (unsigned int) stat->tries_nodial, + (unsigned int) stat->tries_hshake, + (unsigned int) stat->tries_sessns, + (unsigned long) stat->hold_until, + (unsigned long) stat->hold_freqs, + (unsigned long) stat->last_success_out, + (unsigned long) stat->last_success_in); + + return 0; +} + +static int session_stat_update_stsfile(const char *stsname, s_sess_stat *stat) +{ + int rc = 0; + FILE *sts_fp = NULL; + s_sess_stat tmpstat; + bool stsexist = FALSE; + + memset(&tmpstat, '\0', sizeof(s_sess_stat)); + + stsexist = (access(stsname, R_OK) == 0); + + if( (sts_fp = file_open(stsname, stsexist ? "r+" : "w")) == NULL ) + { + logerr("cannot open status file \"%s\"", stsname); + gotoexit(-1); + } + + if( stsexist ) + { + /* Ignore read errors */ + (void)session_stat_read_stsfile(sts_fp, &tmpstat); + + if( ftruncate(fileno(sts_fp), 0) == -1 ) + { + logerr("cannot truncate status file \"%s\"", stsname); + gotoexit(-1); + } + } + + /* + * Update statistic + */ + if( stat->tries == TRIES_RESET ) + tmpstat.tries = 0; + else + tmpstat.tries += stat->tries; + + if( stat->tries_noconn == TRIES_RESET ) + tmpstat.tries_noconn = 0; + else + tmpstat.tries_noconn += stat->tries_noconn; + + if( stat->tries_nodial == TRIES_RESET ) + tmpstat.tries_nodial = 0; + else + tmpstat.tries_nodial += stat->tries_nodial; + + if( stat->tries_noansw == TRIES_RESET ) + tmpstat.tries_noansw = 0; + else + tmpstat.tries_noansw += stat->tries_noansw; + + if( stat->tries_hshake == TRIES_RESET ) + tmpstat.tries_hshake = 0; + else + tmpstat.tries_hshake += stat->tries_hshake; + + if( stat->tries_sessns == TRIES_RESET ) + tmpstat.tries_sessns = 0; + else + tmpstat.tries_sessns += stat->tries_sessns; + + if( stat->hold_until == HOLD_RESET ) + tmpstat.hold_until = 0; + else if( stat->hold_until > tmpstat.hold_until ) + tmpstat.hold_until = stat->hold_until; + + if( stat->hold_freqs == HOLD_RESET ) + tmpstat.hold_freqs = 0; + else if( stat->hold_freqs > tmpstat.hold_freqs ) + tmpstat.hold_freqs = stat->hold_freqs; + + if( stat->last_success_out > tmpstat.last_success_out ) + tmpstat.last_success_out = stat->last_success_out; + + if( stat->last_success_in > tmpstat.last_success_in ) + tmpstat.last_success_in = stat->last_success_in; + + /* + * Write new statistic to the 'sts' file + */ + if( session_stat_write_stsfile(sts_fp, &tmpstat) == -1 ) + { + logerr("error writing status file \"%s\"", stsname); + gotoexit(-1); + } + +exit: + if( sts_fp ) + file_close(sts_fp); + + return rc; +} + +int session_stat_get(s_sess_stat *stat, s_faddr *addr) +{ + FILE *fp; + char *stsname = session_stat_get_stsfile(addr, -1); + + memset(stat, '\0', sizeof(s_sess_stat)); + + if( stsname ) + { + fp = file_open(stsname, "r"); + if( !fp ) + { + free(stsname); + return -1; + } + + (void)session_stat_read_stsfile(fp, stat); + + (void)file_close(fp); + free(stsname); + } + + return 0; +} + +int session_stat_apply_diff(s_faddr addr, s_sess_stat stat) +{ + int rc; + char *stsname = session_stat_get_stsfile(&addr, -1); + + if( !stsname ) + return -1; + + rc = session_stat_update_stsfile(stsname, &stat); + + free(stsname); + return rc; +} + +int session_stat_update(s_faddr *addr, s_sess_stat *stat, bool caller, int rc) +{ + char *stsname; + + /* + * Update sessions statistic depending on session + * return code. The latter must be one of BFERR + * values. Warning, stat structure might allready + * contain desired settings! + */ + if( rc == BFERR_NOERROR ) + { + if( caller ) + stat->last_success_out = time(NULL); + else + stat->last_success_in = time(NULL); + + session_stat_reset_counters(stat); + } + else + { + if( caller ) + { + stat->tries++; + if( rc == BFERR_HANDSHAKE_ERROR ) + stat->tries_hshake++; + if( rc == BFERR_CANT_CONNECT14 ) + stat->tries_noansw++; + if( rc == BFERR_CANT_CONNECT13 ) + stat->tries_nodial++; + if( BFERR_CANT_CONNECT10 <= rc && rc <= BFERR_CANT_CONNECT19 ) + stat->tries_noconn++; + if( rc >= BFERR_CONNECT_TOOLOW ) + stat->tries_sessns++; + + /* Reset some counters */ + if( rc >= BFERR_CONNECT_TOOLOW ) + { + stat->tries_noansw = TRIES_RESET; + stat->tries_noconn = TRIES_RESET; + } + if( rc > BFERR_HANDSHAKE_ERROR ) + stat->tries_hshake = TRIES_RESET; + } + } + + stsname = session_stat_get_stsfile(addr, -1); + if( !stsname ) + return -1; + + rc = session_stat_update_stsfile(stsname, stat); + + free(stsname); + return rc; +} + diff --git a/source/bforce/u_crc.c b/source/bforce/u_crc.c new file mode 100644 index 0000000..ad1ee52 --- /dev/null +++ b/source/bforce/u_crc.c @@ -0,0 +1,206 @@ +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ +/* */ +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ +/* */ +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +unsigned long TableCRC32CCITT[256] = /* CRC polynomial 0xedb88320 */ +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +/* Used by Xmodem and Zmodem */ +unsigned short TableCRC16Xmodem[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +/* Used by Hydra */ +unsigned short TableCRC16CCITT[256] = /* CRC polynomial 0x8408 */ +{ + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, + 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, + 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, + 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, + 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, + 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, + 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, + 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, + 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, + 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, + 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, + 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, + 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, + 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, + 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, + 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, + 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, + 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, + 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, + 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, + 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, + 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, + 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, + 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, + 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, + 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, + 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, + 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, + 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, + 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +/***************************************************************************** + * Calculate CCITT CRC-32 of the data block. Used in Zmodem, Hydra protocols. + * + * Arguments: + * buffer pointer to the staring of data block + * buflen data block size + * + * Return value: + * CRC-32 + */ +unsigned long getcrc32ccitt(const unsigned char *buffer, size_t buflen) +{ + unsigned long crc = 0xffffffffL; + + for( ; buflen-- > 0; buffer++ ) + crc = TableCRC32CCITT[((int) crc ^ (*buffer)) & 0xff] ^ ((crc >> 8) & 0x00ffffff); + + return crc; +} + +/***************************************************************************** + * Calculate CRC-16 of the data block. Used in Xmodem, Zmodem protocols. + * + * Arguments: + * buffer pointer to the staring of data block + * buflen data block size + * + * Return value: + * CRC-16 + */ +unsigned short getcrc16xmodem(const unsigned char *buffer, size_t buflen) +{ + unsigned short crc = 0; + + for( ; buflen-- > 0; buffer++ ) + crc = TableCRC16Xmodem[(((crc >> 8) & 0xff) ^ (*buffer)) & 0xff] ^ (crc << 8); + + return crc; +} + +/***************************************************************************** + * Calculate CCITT CRC-16 of the data block. Used in Hydra protocol. + * + * Arguments: + * buffer pointer to the staring of data block + * buflen data block size + * + * Return value: + * CRC-16 + */ +unsigned short getcrc16ccitt(const unsigned char *buffer, size_t buflen) +{ + unsigned short crc = 0xffff; + + for( ; buflen-- > 0; buffer++ ) + crc = TableCRC16CCITT[(crc ^ (*buffer)) & 0xff] ^ ((crc >> 8) & 0x00ff); + + return crc; +} diff --git a/source/bforce/u_file.c b/source/bforce/u_file.c new file mode 100644 index 0000000..4c94b45 --- /dev/null +++ b/source/bforce/u_file.c @@ -0,0 +1,312 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +struct fnctab { + const char *find; + const char *repl; +} fnctab[] = { + { ".tar.gz", ".tgz" }, + { ".tar.bz2", ".tbz" }, + { ".html", ".htm" }, + { ".desc", ".dsc" }, + { NULL, NULL } +}; + +/***************************************************************************** + * Lock whole file for reading or writing + * + * Arguments: + * fp pointer to the opened file FILE structure + * exclusive lock file for exclusive or shared access + * + * Return value: + * zero value on success and -1 on errors + */ +int file_lock(FILE *fp, bool exclusive) +{ +#ifdef USE_FLOCK + if( flock(fileno(fp), (exclusive ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1 ) + return -1; +#else + struct flock flck; + + memset(&flck, '\0', sizeof(struct flock)); + flck.l_whence = SEEK_SET; + flck.l_start = 0; + flck.l_len = 0; + flck.l_type = exclusive ? F_WRLCK : F_RDLCK; + + if( fcntl(fileno(fp), F_SETLK, &flck) == -1 ) + return -1; +#endif + + return 0; +} + +/***************************************************************************** + * Unlock file + * + * Arguments: + * fp pointer to the opened file FILE structure + * + * Return value: + * None + */ +void file_unlock(FILE *fp) +{ +#ifdef USE_FLOCK + (void)flock(fileno(fp), LOCK_UN | LOCK_NB) +#else + struct flock flck; + + memset(&flck, '\0', sizeof(struct flock)); + flck.l_whence = SEEK_SET; + flck.l_start = 0; + flck.l_len = 0; + flck.l_type = F_UNLCK; + + (void)fcntl(fileno(fp), F_SETLK, &flck); +#endif +} + +/***************************************************************************** + * Lock whole file for reading or writing, do some number of tries before + * giving up + * + * Arguments: + * fp pointer to the opened file FILE structure + * exclusive lock file for exclusive or shared access + * + * Return value: + * zero value on success and -1 on errors + */ +int file_lock_wait(FILE *fp, bool exclusive) +{ + int tries; + + for( tries = 0; tries < 50; tries++ ) + { + if( file_lock(fp, exclusive) == 0 ) + return 0; + usleep(200); + } + + return -1; +} + +bool file_name_issafe(int ch) +{ + if( ch == '!' ) return TRUE; + if( ch == '"' ) return TRUE; + if( ch == '#' ) return TRUE; + if( ch == '$' ) return TRUE; + if( ch == '&' ) return TRUE; + if( ch == '+' ) return TRUE; + if( ch == ',' ) return TRUE; + if( ch == '-' ) return TRUE; + if( ch == '.' ) return TRUE; + if( ch == '@' ) return TRUE; + if( ch == '_' ) return TRUE; + if( ch == '^' ) return TRUE; + if( ch == '~' ) return TRUE; + if( ch > 47 && ch < 58 ) return TRUE; /* '0'-'9' */ + if( ch > 64 && ch < 91 ) return TRUE; /* 'A'-'Z' */ + if( ch > 96 && ch < 123 ) return TRUE; /* 'a'-'z' */ + if( ch > 127 && ch < 256 ) return TRUE; /* Hmm. :) */ + + return FALSE; +} + +char *file_name_makesafe(char *filename) +{ + char *p; + + for( p = filename; *p; p++ ) + if( !file_name_issafe((unsigned char)(*p)) ) *p = '_'; + + return filename; +} + +char *file_getname(char *filename) +{ + char *p = strrchr(filename, '/'); + return p ? p + 1 : filename; +} + +char *file_gettmp(void) +{ + char *tmp = xstrcpy("/tmp/bforce-XXXXXX"); + char *res = mktemp(tmp); + + if( !res ) + free(tmp); + + return res; +} + +char *file_get_dos_name(char *buffer, const char *filename) +{ + char *copy = xstrcpy(filename); + char *p; + int i; + int extension_length = 0; + + for( i = 0; fnctab[i].find; i++ ) + { + if( (p = strstr(copy, fnctab[i].find)) ) + { + *p = '\0'; + strcat(copy, fnctab[i].repl); + strcat(copy, p + strlen(fnctab[i].find)); + break; + } + } + + /* + * Make sure, there is no '.' characters + * except extension separator point + */ + for( p = copy + strlen(copy) - 1; p >= copy; p-- ) + { + if( (unsigned char)(*p) <= ' ' || *p == '*' || *p == '?' ) + *p = '_'; + else if( *p == '.' ) + { + if( 4 >= strlen(p) && strlen(p) > 1 && !extension_length ) + extension_length = strlen(p + 1); + else + *p = '_'; + } + } + + if( (extension_length > 0 && strlen(copy) <= 9 + extension_length) + || (extension_length == 0 && strlen(copy) <= 8) ) + strcpy(buffer, copy); + else + { + strncpy(buffer, copy, 5); + if( extension_length > 0 ) + strncpy(buffer + 6, copy + strlen(copy) - 3 - extension_length, 6); + else + strncpy(buffer + 6, copy + strlen(copy) - 2, 2); + buffer[5] = '~'; + buffer[12] = '\0'; + } + + free(copy); copy = NULL; + + /* + * Make it lower case + */ + string_tolower(buffer); + + if( !extension_length ) + buffer[8] = '\0'; + + return buffer; +} + +bool is_directory(const char *dirname) +{ + struct stat st; + + if( stat(dirname, &st) == -1 ) + return FALSE; + + return S_ISDIR(st.st_mode) ? TRUE : FALSE; +} + +bool is_regfile(const char *filename) +{ + struct stat st; + + if( stat(filename, &st) == -1 ) + return FALSE; + + return S_ISREG(st.st_mode) ? TRUE : FALSE; +} + +int directory_create(const char *dirname, mode_t access_mode) +{ + char tmpname[BFORCE_MAX_PATH+1]; + char *p = tmpname; + bool eol = FALSE; + + strnxcpy(tmpname, dirname, sizeof(tmpname)); + + while( *p && !eol ) + { + while( *p && *p != '/' ) ++p; + + if( *p ) + *p = '\0'; + else + eol = TRUE; + + if( !is_directory(tmpname) ) + { + if( mkdir(tmpname, access_mode) == -1 && errno != EEXIST ) + return -1; + (void)chmod(tmpname, access_mode); + } + + if( !eol ) + *p++ = '/'; + } + + return 0; +} + +FILE *file_open(const char *path, const char *mode) +{ + FILE *stream; + bool is_write; + + ASSERT(path); + ASSERT(mode && (*mode == 'r' || *mode == 'w' || *mode == 'a')); + + stream = fopen(path, mode); + if( !stream ) + return NULL; + + is_write = (*mode != 'r') ? TRUE : FALSE; + + /* Try to lock it */ + if( file_lock(stream, is_write) == 0 ) + return stream; + + /* If we can't physically lock file, just send it as is */ + if ( errno == EOPNOTSUPP || errno == EINVAL ) + return stream; + + /* Do second try */ + if( file_lock_wait(stream, is_write) == 0 ) + return stream; + + fclose(stream); + return NULL; +} + +int file_close(FILE *stream) +{ + ASSERT(stream); + + file_unlock(stream); + return fclose(stream); +} + diff --git a/source/bforce/u_ftn.c b/source/bforce/u_ftn.c new file mode 100644 index 0000000..2c595df --- /dev/null +++ b/source/bforce/u_ftn.c @@ -0,0 +1,525 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +#define ADDRNUM_MIN 0x0000 +#define ADDRNUM_MAX 0x7fff + +static int addrstr2int(const char *s) +{ + int val = atoi(s); + + if( val < ADDRNUM_MIN ) + val = ADDRNUM_MIN; + else if( val > ADDRNUM_MAX ) + val = ADDRNUM_MAX; + + return val; +} + +char *addrint2str(char *buffer, int val) +{ + if( val == -1 ) + strcpy(buffer, "*"); + else if( val < ADDRNUM_MIN ) + strcpy(buffer, "MIN"); + else if( val > ADDRNUM_MAX ) + strcpy(buffer, "MAX"); + else + sprintf(buffer, "%d", val); + + return buffer; +} + +static int ftn_addrparse_fido(s_faddr *addr, const char *s, bool wildcard) +{ + bool badaddr = 0; + bool stop = 0; + bool gotzone = 0; + bool gotnet = 0; + bool gotnode = 0; + bool gotpoint = 0; + const char *p = s; + + ASSERT(s != NULL); + + while( !stop && !badaddr ) + { + switch(*p) { + case ':': + if( !gotzone && isdigit(*s) ) + { + gotzone = 1; + addr->zone = addrstr2int(s); + s = ++p; + } + else if( !gotzone && wildcard && *s == '*' ) + { + gotzone = 1; + addr->zone = -1; + s = ++p; + } + else badaddr = 1; + break; + + case '/': + if( !gotnet && isdigit(*s) ) + { + gotnet = 1; + addr->net = addrstr2int(s); + s = ++p; + } + else if( !gotnet && wildcard && *s == '*' ) + { + gotnet = 1; + addr->net = -1; + s = ++p; + } + else if( *s != '/' ) badaddr = 1; + else ++p; + break; + + case '.': + if( *s == '/' ) ++s; + if( !gotnode && isdigit(*s) ) + { + gotnode = 1; + addr->node = addrstr2int(s); + s = ++p; + } + else if( !gotnode && wildcard && *s == '*' ) + { + gotnode = 1; + addr->node = -1; + s = ++p; + } + else if( *s != '.' ) badaddr = 1; + else ++p; + break; + + case '@': + case '\0': + if( gotzone && !gotnet ) { badaddr = 1; break; } + + if( *s == '/' ) + { + ++s; + if( !gotnode && isdigit(*s) ) + { + gotnode = 1; + addr->node = addrstr2int(s); + } + else if( !gotnode && wildcard && *s == '*' ) + { + gotnode = 1; + addr->node = -1; + } + else badaddr = 1; + } + else if( *s == '.' ) + { + ++s; + if( !gotpoint && isdigit(*s) ) + { + gotpoint = 1; + addr->point = addrstr2int(s); + } + else if( !gotpoint && wildcard && *s == '*' ) + { + gotpoint = 1; + addr->point = -1; + } + else badaddr = 1; + } + else if( isdigit(*s) ) + { + if( !gotnode ) + { + gotnode = 1; + addr->node = addrstr2int(s); + } + else if( !gotpoint ) + { + gotpoint = 1; + addr->point = addrstr2int(s); + } + else badaddr = 1; + } + else if( wildcard && *s == '*' ) + { + if( !gotnode ) + { + gotnode = 1; + addr->node = -1; + } + else if( !gotpoint ) + { + gotpoint = 1; + addr->point = -1; + } + else badaddr = 1; + } + else badaddr = 1; + stop = 1; + break; + + default: + if( isdigit(*p) || (wildcard && *p == '*') ) + { ++p; } + else + { badaddr = 1; } + } + } + + if( !badaddr && *p++ == '@' && *p ) + { + strnxcpy(addr->domain, string_printable(p), sizeof(addr->domain)); + } + + return badaddr; +} + +static int ftn_addrparse_inet(s_faddr *addr, const char *s, bool wildcard) +{ + bool badaddr = 0; + bool stop = 0; + bool gotzone = 0; + bool gotnet = 0; + bool gotnode = 0; + bool gotpoint = 0; + const char *p = s; + + ASSERT(s != NULL); + + while( !stop && !badaddr ) + { + if( *p == '.' || *p == '\0' ) + { + if( *p == '\0' ) stop = 1; + + switch(*s++) { + case 'p': + case 'P': + if( !gotpoint && isdigit(*s) ) + { + gotpoint = 1; + addr->point = addrstr2int(s); + s = ++p; + } + else badaddr = 1; + break; + case 'f': + case 'F': + if( !gotnet && !gotzone && !gotnode && isdigit(*s) ) + { + gotnode = 1; + addr->node = addrstr2int(s); + s = ++p; + } + else badaddr = 1; + break; + case 'n': + case 'N': + if( gotnode && !gotzone && !gotnet && isdigit(*s) ) + { + gotnet = 1; + addr->net = addrstr2int(s); + s = ++p; + } + else badaddr = 1; + break; + case 'z': + case 'Z': + if( gotnode && gotnet && !gotzone && isdigit(*s) ) + { + gotzone = 1; + addr->zone = addrstr2int(s); + if( *p++ == '.' && *p ) + { + strnxcpy(addr->domain, string_printable(p), sizeof(addr->domain)); + } + stop = 1; + } + else badaddr = 1; + break; + default: + badaddr = 1; + break; + } + } + else + { + ++p; + } + } + + return badaddr; +} + +/***************************************************************************** + * Parse FTN address (can be specified in traditional form (X:X/X.X) as + * well as in domain form (pX.fX.nX.zX.domain)) + * + * Arguments: + * addr we will put parsed address here + * s pointer to the null-terminated string with address + * wildcard set FALSE if you want forbid wildcards processing + * + * Return value: + * zero value if addres was parsed successfuly, and non-zero if wasn't + */ +int ftn_addrparse(s_faddr *addr, const char *s, bool wildcard) +{ + const char *p; + bool stop = 0; + bool badaddr = 0; + + ASSERT(s != NULL); + + memset(addr, '\0', sizeof(s_faddr)); + + /* + * Detect the address form (domain or traditional) + */ + for( p = s; *p && !stop && !badaddr; p++ ) + { + switch( *p ) { + case '*': + if( wildcard == FALSE ) badaddr = 1; + case '@': + stop = 1; + case ':': + case '/': + case '.': + addr->inetform = 0; + break; + case 'p': + case 'P': + case 'f': + case 'F': + addr->inetform = 1; + stop = 1; + break; + default: + if( !isdigit(*p) ) badaddr = 1; + } + } + + if( !badaddr ) + { + addr->zone = DEFAULT_ZONE; + addr->net = DEFAULT_NET; + addr->node = DEFAULT_NODE; + addr->point = 0; + + if( addr->inetform ) + badaddr = ftn_addrparse_inet(addr, s, wildcard); + else + badaddr = ftn_addrparse_fido(addr, s, wildcard); + } + + return badaddr; +} + +char *ftn_addrstr_fido(char *buf, s_faddr addr) +{ + char str1[10]; + char str2[10]; + char str3[10]; + char str4[10]; + + if( addr.point ) + { + sprintf(buf, "%s:%s/%s.%s", + addrint2str(str1, addr.zone), addrint2str(str2, addr.net), + addrint2str(str3, addr.node), addrint2str(str4, addr.point)); + } + else + { + sprintf(buf, "%s:%s/%s", + addrint2str(str1, addr.zone), addrint2str(str2, addr.net), + addrint2str(str3, addr.node)); + } + + if( *addr.domain ) + { + strnxcat(buf, "@", BF_MAXADDRSTR); + strnxcat(buf, addr.domain, BF_MAXADDRSTR); + } + + return buf; +} + +char *ftn_addrstr_inet(char *buf, s_faddr addr) +{ + char str1[10]; + char str2[10]; + char str3[10]; + char str4[10]; + + if( addr.point ) + { + sprintf(buf, "p%s.f%s.n%s.z%s", + addrint2str(str1, addr.point), addrint2str(str2, addr.node), + addrint2str(str3, addr.net), addrint2str(str4, addr.zone)); + } + else + { + sprintf(buf, "f%s.n%s.z%s", + addrint2str(str1, addr.node), addrint2str(str2, addr.net), + addrint2str(str3, addr.zone)); + } + + if( *addr.domain ) + { + strnxcat(buf, ".", BF_MAXADDRSTR); + strnxcat(buf, addr.domain, BF_MAXADDRSTR); + } + + return buf; +} + +/***************************************************************************** + * Put FTN address as the null-terminated string to the buffer + * + * Arguments: + * buf pointer to the destination buffer (must be at least + * BF_MAXADDRSTR bytes length) + * addr FTN address + * + * Return value: + * pointer to the buffer start + */ +char *ftn_addrstr(char *buf, s_faddr addr) +{ + ASSERT(buf != NULL); + + return addr.inetform ? ftn_addrstr_inet(buf, addr) + : ftn_addrstr_fido(buf, addr); +} + +/***************************************************************************** + * Compare two FTN addresses + * + * Arguments: + * addr1 first FTN address + * addr2 second FTN address + * + * Return value: + * zero value if addresses are equal, and non-zero if not + */ +int ftn_addrcomp(s_faddr addr1, s_faddr addr2) +{ + return !( addr1.zone == addr2.zone && addr1.net == addr2.net + && addr1.node == addr2.node && addr1.point == addr2.point ); +} + +/***************************************************************************** + * Compare two FTN addresses + * + * Arguments: + * addr1 first FTN address + * operator logical operator (EQ|GT|LT) + * addr2 second FTN address + * + * Return value: + * zero value if expression is true, and non-zero if not + */ +int ftn_addrcomp_logic(s_faddr addr1, int operator, s_faddr addr2) +{ + int i; + int matr1[4] = { addr1.zone, addr1.net, addr1.node, addr1.point }; + int matr2[4] = { addr2.zone, addr2.net, addr2.node, addr2.point }; + + for( i = 0; i < 4; i++ ) + { + switch(operator) { + case ADDR_EQ: + if( matr1[i] != matr2[i] ) + return 1; + break; + case ADDR_GT: + if( matr1[i] > matr2[i] ) + return 0; + else if( matr1[i] < matr2[i] ) + return 1; + break; + case ADDR_LT: + if( matr1[i] < matr2[i] ) + return 0; + else if( matr1[i] > matr2[i] ) + return 1; + break; + default: + ASSERT(0); + } + } + + return 0; +} +/***************************************************************************** + * Compare two FTN addresses (second address can contain wildcards) + * + * Arguments: + * addr first FTN address + * mask second FTN address (with wildcards) + * + * Return value: + * zero value if addresses are equal, and non-zero if not + */ +int ftn_addrcomp_mask(s_faddr addr, s_faddr mask) +{ + return !( (addr.zone == mask.zone || mask.zone == -1) + && (addr.net == mask.net || mask.net == -1) + && (addr.node == mask.node || mask.node == -1) + && (addr.point == mask.point || mask.point == -1) ); +} + +/***************************************************************************** + * Get the metric of matching two addresses + * + * Arguments: + * addr1 first FTN address + * addr2 second FTN address + * + * Return value: + * from 0 to 4 (0 - no matching, 4 - equal addresses) + */ +int ftn_addrsmetric(s_faddr addr1, s_faddr addr2) +{ + int metric = 0; + + if( addr1.zone == addr2.zone ) + { + ++metric; + if( addr1.net == addr2.net ) + { + ++metric; + if( addr1.node == addr2.node ) + { + ++metric; + if( addr1.point == addr2.point ) + { + ++metric; + } + } + } + } + + return metric; +} + diff --git a/source/bforce/u_md5.c b/source/bforce/u_md5.c new file mode 100644 index 0000000..af1cc47 --- /dev/null +++ b/source/bforce/u_md5.c @@ -0,0 +1,336 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +/* Data structure for MD5 (Message-Digest) computation */ +typedef struct { + int chunks; /* Number of 64 byte chunks */ + unsigned int buf[4]; +} s_md5; + +/* F, G, H and I are basic MD5 functions */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (unsigned int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (unsigned int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (unsigned int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (unsigned int)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +#ifdef __STDC__ +#define UL(x) x##U +#else +#define UL(x) x +#endif + +/***************************************************************************** + * Initialise MD5 structure + * + * Arguments: + * md pointer to the MD5 structure + * + * Return value: + * None + */ +static void md5_init(s_md5 *md) +{ + md->chunks = 0; + + md->buf[0] = (unsigned int)0x67452301; + md->buf[1] = (unsigned int)0xefcdab89; + md->buf[2] = (unsigned int)0x98badcfe; + md->buf[3] = (unsigned int)0x10325476; +} + +/***************************************************************************** + * Process next data chunk + * + * Arguments: + * md pointer to the MD5 structure + * buffer pointer to the data chunk (must be 64 bytes) + * + * Return value: + * None + */ +static void md5_update(s_md5 *md, const unsigned char *buffer) +{ + int i; + unsigned int in[16]; + unsigned int a = md->buf[0]; + unsigned int b = md->buf[1]; + unsigned int c = md->buf[2]; + unsigned int d = md->buf[3]; + + ++md->chunks; + + /* Unpack buffer */ + for( i = 0; i < 16; i++ ) + { + in[i] = ((unsigned int)(buffer[0]) ) + | ((unsigned int)(buffer[1]) << 8 ) + | ((unsigned int)(buffer[2]) << 16) + | ((unsigned int)(buffer[3]) << 24); + buffer += 4; + } + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ + FF( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ + FF( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ + FF( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ + FF( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ + FF( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ + FF( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ + FF( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ + FF( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ + FF( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ + FF( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ + FF( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ + FF( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ + FF( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ + FF( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ + FF( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ + GG( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ + GG( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ + GG( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ + GG( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ + GG( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */ + GG( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ + GG( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ + GG( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ + GG( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ + GG( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ + GG( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ + GG( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ + GG( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ + GG( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ + GG( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ + HH( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ + HH( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ + HH( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ + HH( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ + HH( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ + HH( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ + HH( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ + HH( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ + HH( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ + HH( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ + HH( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */ + HH( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ + HH( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ + HH( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ + HH( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ + II( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ + II( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ + II( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ + II( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ + II( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ + II( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ + II( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ + II( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ + II( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ + II( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ + II( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ + II( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ + II( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ + II( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ + II( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ + + md->buf[0] += a; + md->buf[1] += b; + md->buf[2] += c; + md->buf[3] += d; +} + +/***************************************************************************** + * Compute MD5 digest (RFC-1321) + * + * Arguments: + * md pointer to the MD5 structure + * digest pointer to the resulting digest buffer (must be 16 bytes) + * data pointer to the source data + * length source data length + * + * Return value: + * None + */ +static void md5_compute(s_md5 *md, const unsigned char *data, size_t length, + unsigned char *digest) +{ + unsigned char buffer[64]; + int i; + + while( length >= 64 ) + { + md5_update(md, data); + data += 64; + length -= 64; + } + + memcpy(buffer, data, length); + buffer[length] = 0x80; + memset(buffer + length + 1, '\0', 63 - length); + + if( length > 55 ) + { + md5_update(md, buffer); + memset(buffer, '\0', 64); + --md->chunks; + } + + length += (md->chunks * 64); + length <<= 3; + + buffer[56] = (unsigned char)((length ) & 0xff); + buffer[57] = (unsigned char)((length >> 8 ) & 0xff); + buffer[58] = (unsigned char)((length >> 16) & 0xff); + buffer[59] = (unsigned char)((length >> 24) & 0xff); + + md5_update(md, buffer); + + for( i = 0; i < 4; i++ ) + { + unsigned int x = md->buf[i]; + *digest++ = (unsigned char)((x ) & 0xff); + *digest++ = (unsigned char)((x >> 8 ) & 0xff); + *digest++ = (unsigned char)((x >> 16) & 0xff); + *digest++ = (unsigned char)((x >> 24) & 0xff); + } +} + +void md5_get(const unsigned char *data, size_t length, unsigned char *digest) +{ + s_md5 md; + + md5_init(&md); + md5_compute(&md, data, length, digest); +} + +/***************************************************************************** + * Compute CRAM-MD5 digest (RFC-2195). It is produced by calculating + * + * MD5((secret XOR opad), MD5((secret XOR ipad), challengedata)) + * + * where MD5 is chosen hash function, ipad and opad are 36 hex and 5C hex + * and secret is null-padded to a length of 64 bytes. If the secret is + * longer than 64 bytes, the hash-function digest of the secret is used as + * an input + * + * Arguments: + * secret pointer to the null-terminated secret string (e.g. password) + * challenge pointer to the challenge data + * challenge_length length of the challenge data + * digest pointer to the resulting digest buffer (must be 16 bytes) + * + * Return value: + * None + */ +void md5_cram_get(const unsigned char *secret, const unsigned char *challenge, + int challenge_length, unsigned char *digest) +{ + int i; + unsigned char secret_md5[16]; + int secret_length = strlen(secret); + unsigned char osecret[64]; + unsigned char isecret[64]; + s_md5 md; + + /* + * If the secret length is longer 64 bytes + * use MD5 digest of the secret as input + */ + if( secret_length > 64 ) + { + md5_get(secret, secret_length, secret_md5); + secret = secret_md5; + secret_length = 16; + } + + memcpy(osecret, secret, secret_length); + memcpy(isecret, secret, secret_length); + memset(osecret + secret_length, '\0', 64 - secret_length); + memset(isecret + secret_length, '\0', 64 - secret_length); + + for( i = 0; i < 64; i++ ) + { + osecret[i] ^= 0x5c; + isecret[i] ^= 0x36; + } + + /* + * Compute HASH((secret XOR ipad), challenge) + */ + md5_init(&md); + md5_update(&md, isecret); + md5_compute(&md, challenge, challenge_length, secret_md5); + + /* + * Compute HASH((secret XOR opad), secret_md5) + */ + md5_init(&md); + md5_update(&md, osecret); + md5_compute(&md, secret_md5, 16, digest); +} + diff --git a/source/bforce/u_misc.c b/source/bforce/u_misc.c new file mode 100644 index 0000000..e2f1967 --- /dev/null +++ b/source/bforce/u_misc.c @@ -0,0 +1,336 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +/* + * Array of mask aliases, you may add new values if you need + */ +struct magfname { + const char *alias; + const char *masks; +} magfname[] = { + { "netmail", "*.pkt *.out *.cut *.hut *.dut *.iut" }, + { "arcmail", "*.su? *.mo? *.tu? *.we? *.th? *.fr? *.sa?" }, + { "ticfile", "*.tic" }, + { "archive", "*.tgz *.bz2 *.zip *.rar *.arj *.lha *.ha" }, + { NULL, NULL } +}; + +/***************************************************************************** + * Allocate memory, check for errors + * + * Arguments: + * size number of bytes to allocate + * + * Return value: + * Pointer to the allocated memory + */ +void *xmalloc(size_t size) +{ + char *tmp; + + if( size <= 0 ) + { + log("requested to allocate %ld bytes", (long)size); + size = 1; + } + + if( (tmp = (char *)malloc(size)) == NULL ) + { + log("failed to allocate %ld bytes -> abort", (long)size); + abort(); + } + + return tmp; +} + +/***************************************************************************** + * Change the size of allready allocated memory + * + * Arguments: + * buf pointer to the memory block which size we want change + * size new block size + * + * Return value: + * Pointer to the reallocated memory + */ +void *xrealloc(void *buf, size_t size) +{ + char *tmp; + + if( size <= 0 ) + { + tmp = NULL; + log("requested to reallocate %ld bytes", (long)size); + if( buf ) free(buf); + } + else if( (tmp = (char*)(buf ? realloc(buf, size) : malloc(size))) == NULL ) + { + log("failed to reallocate %ld bytes -> abort", size); + abort(); + } + + return tmp; +} + +/***************************************************************************** + * Make copy of memory block + * + * Arguments: + * buffer pointer to the memory block which we want to duplicate + * size memory block size + * + * Return value: + * Pointer to the memory block copy (must be freed) + */ +void *xmemcpy(const void *buffer, size_t buflen) +{ + void *ptr = xmalloc(buflen); + + memcpy(ptr, buffer, buflen); + + return ptr; +} + +/***************************************************************************** + * Compare string for matching to the mask. Special characters for the mask: + * '?' - any one chracter (except '\0'); + * '*' - any group of chracters (including '\0'); + * '\' - next chracter will be compared directly (including '?' and '*') + * + * Arguments: + * str pointer to the null-terminated string + * mask pointer to the null-terminated mask + * + * Return value: + * zero value if string matchs pattern, and non-zero if not + */ +int strcasemask(const char *str, const char *mask) +{ + const char *s, *m; + char c; + + ASSERT(str != NULL && mask != NULL); + + s = str; + m = mask; + + while( *s ) + { + switch( c = *m++ ) { + case '\0': + return 1; + + case '\\': + if( *m ) + { + if( toupper(*m++) != toupper(*s++) ) + return 1; + } + else if( *s++ == '\\' && *s == '\0' ) + return 0; + else + return 1; + break; + + case '?': + ++s; + break; + + case '*': + if( *m ) + { + do { + /* anti stack overflow */ + while( *m == '*' ) m++; + + if( *m != '\\' && *m != '?' ) + while( *s && toupper(*s) != toupper(*m) ) ++s; + + if( *s && !strcasemask(s, m) ) + return 0; + } while( *s++ ); + + return 1; + } + return 0; + + default: + if( toupper(c) != toupper(*s++) ) + return 1; + } + } + + return( *s != '\0' || *m != '\0' ); +} + +/***************************************************************************** + * Check whether masks list (e.g. "*.zip *.rar *.tic") conforms to the file + * name. For the masks description look string_pattern() info. + * + * Arguments: + * masks pointer to the null-terminated masks list + * str pointer to the null-terminated file name + * + * Return value: + * non-zero value if file name match masks, and zero if not + */ +int checkmasks(const char *masks, const char *str) +{ + int i = 0, not = 0; + char *p = NULL; + char *n = NULL; + char *strs; + int yield = 1; + + ASSERT(masks != NULL && str != NULL); + + strs = xstrcpy(masks); + + for( p = string_token(strs, &n, NULL, 1); p; + p = string_token(NULL, &n, NULL, 1) ) + { + DEB((D_INFO, "checkmasks: checking \"%s\" in \"%s\"", str, p)); + + not = ( p[0] == '!' ); + + if( not ) + ++p; + + if( p[0] == '%' ) + { + for( i = 0; magfname[i].alias; i++ ) + if( strcasecmp(p+1, magfname[i].alias) == 0 ) + { + if( !checkmasks(magfname[i].masks, str) ) + { + free(strs); + return not; + } + else if( not ) + yield = 0; + + break; + } + } + else if( !strcasemask(str, p) ) + { + free(strs); + return not; + } + else if( not ) + yield = 0; + } + + free(strs); + return yield; +} + +/***************************************************************************** + * Put long integer (4 bytes) to the buffer + * + * Arguments: + * buffer pointer to the destination buffer + * val value that we want put to the buffer + * + * Return value: + * Pointer to the specified buffer + */ +char *buffer_putlong(char *buffer, long val) +{ + buffer[0] = ( ((unsigned long) val) ) & 0xff; + buffer[1] = ( ((unsigned long) val) >> 8 ) & 0xff; + buffer[2] = ( ((unsigned long) val) >> 16 ) & 0xff; + buffer[3] = ( ((unsigned long) val) >> 24 ) & 0xff; + + return buffer; +} + +/***************************************************************************** + * Put integer (2 bytes) to the buffer + * + * Arguments: + * buffer pointer to the destination buffer + * val value that we want put to the buffer + * + * Return value: + * Pointer to the specified buffer + */ +char *buffer_putint(char *buffer, int val) +{ + buffer[0] = ( ((unsigned int) val) ) & 0xff; + buffer[1] = ( ((unsigned int) val) >> 8 ) & 0xff; + + return buffer; +} + +/***************************************************************************** + * Get long integer (4 bytes) from the buffer + * + * Arguments: + * buffer pointer to the buffer + * + * Return value: + * Extracted value + */ +long buffer_getlong(const char *buffer) +{ + return ( (unsigned long) ((unsigned char) buffer[0]) ) + | ( (unsigned long) ((unsigned char) buffer[1]) << 8 ) + | ( (unsigned long) ((unsigned char) buffer[2]) << 16 ) + | ( (unsigned long) ((unsigned char) buffer[3]) << 24 ); +} + +/***************************************************************************** + * Get integer (2 bytes) from the buffer + * + * Arguments: + * buffer pointer to the buffer + * + * Return value: + * Extracted value + */ +int buffer_getint(const char *buffer) +{ + return ( (unsigned int) ((unsigned char) buffer[0]) ) + | ( (unsigned int) ((unsigned char) buffer[1]) << 8 ); +} + +void printf_usage(const char *ident, const char *fmt, ...) +{ + va_list args; + + if( ident ) + printf("%s %s %s\n\n", BF_BANNERVER, ident, BF_COPYRIGHT); + else + printf("%s %s\n\n", BF_BANNERVER, BF_COPYRIGHT); + + if( fmt ) + { + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + } + else + printf("Sorry, no usage information available\n\n"); + + printf("Mail bug reports to \n"); + + fflush(stdout); +} + +/* end of u_misc.c */ diff --git a/source/bforce/u_pkt.c b/source/bforce/u_pkt.c new file mode 100644 index 0000000..85192a9 --- /dev/null +++ b/source/bforce/u_pkt.c @@ -0,0 +1,220 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +/* + * Packet header offsets + */ +#define PKTHDR_ORIGNODE 0 +#define PKTHDR_DESTNODE 2 +#define PKTHDR_YEAR 4 +#define PKTHDR_MONTH 6 +#define PKTHDR_DAY 8 +#define PKTHDR_HOUR 10 +#define PKTHDR_MINUTE 12 +#define PKTHDR_SECOND 14 +#define PKTHDR_BAUD 16 +#define PKTHDR_PKTTYPE 18 +#define PKTHDR_ORIGNET 20 +#define PKTHDR_DESTNET 22 +#define PKTHDR_PRODCODELOW 24 +#define PKTHDR_REVMAJOR 25 +#define PKTHDR_PASSWORD 26 +#define PKTHDR_QORIGZONE 34 +#define PKTHDR_QDESTZONE 36 +#define PKTHDR_AUXNET 38 +#define PKTHDR_CWVALIDCOPY 40 +#define PKTHDR_PRODCODEHIGH 42 +#define PKTHDR_REVMINOR 43 +#define PKTHDR_CAPABILWORD 44 +#define PKTHDR_ORIGZONE 46 +#define PKTHDR_DESTZONE 48 +#define PKTHDR_ORIGPOINT 50 +#define PKTHDR_DESTPOINT 52 +#define PKTHDR_PRODDATA 54 + +#define PKTHDR_SIZE 58 + +/* + * Packed message header offsets + */ +#define PKTMSGHDR_PKTTYPE 0 +#define PKTMSGHDR_ORIGNODE 2 +#define PKTMSGHDR_DESTNODE 4 +#define PKTMSGHDR_ORIGNET 6 +#define PKTMSGHDR_DESTNET 8 +#define PKTMSGHDR_ATTR 10 +#define PKTMSGHDR_COST 12 +#define PKTMSGHDR_DATE 14 /* 20 bytes */ +#define PKTMSGHDR_TOUSER 24 /* 36 bytes */ +#define PKTMSGHDR_FROMUSER 60 /* 36 bytes */ +#define PKTMSGHDR_SUBJECT 96 /* 72 bytes */ + +#define PKTMSGHDR_SIZE 168 + +/* + * Message attributes + */ +#define MSGATTR_PVT 0x0001 +#define MSGATTR_CRASH 0x0002 +#define MSGATTR_RECD 0x0004 +#define MSGATTR_SENT 0x0008 +#define MSGATTR_FILEATTACH 0x0010 +#define MSGATTR_INTRANSIT 0x0020 +#define MSGATTR_ORPHAN 0x0040 +#define MSGATTR_KILLSENT 0x0080 +#define MSGATTR_LOCAL 0x0100 +#define MSGATTR_HOLD 0x0200 +#define MSGATTR_RESERVED 0x0400 +#define MSGATTR_FILEREQ 0x0800 +#define MSGATTR_RREQ 0x1000 +#define MSGATTR_IRRR 0x2000 +#define MSGATTR_AUDIT 0x4000 +#define MSGATTR_UPDATEREQ 0x8000 +#define MSGATTR_NOTZEROED ( MSGATTR_PVT | MSGATTR_CRASH \ + | MSGATTR_FILEATTACH | MSGATTR_RESERVED \ + | MSGATTR_RREQ | MSGATTR_IRRR | MSGATTR_AUDIT ) + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +static char *pkt_putword(char *buf, int val) +{ + buf[0] = ( ((unsigned int) val) ) & 0xff; + buf[1] = ( ((unsigned int) val) >> 8 ) & 0xff; + + return buf; +} + +static char *pkt_putbyte(char *buf, int val) +{ + buf[0] = ( ((unsigned int) val) ) & 0xff; + + return buf; +} + +static int pkt_getword(const char *buf) +{ + return ( (unsigned int) ((unsigned char) buf[0]) ) + | ( (unsigned int) ((unsigned char) buf[1]) << 8 ); +} + +static char *pkt_putpktheader(char *pkthdr_buffer, const s_packet *pkt) +{ + time_t now = localtogmt(time(NULL)); + struct tm *ptm = localtime(&now); + + memset(pkthdr_buffer, '\0', PKTHDR_SIZE); + + pkt_putword(pkthdr_buffer + PKTHDR_ORIGNODE, pkt->orig.node); + pkt_putword(pkthdr_buffer + PKTHDR_DESTNODE, pkt->dest.node); + pkt_putword(pkthdr_buffer + PKTHDR_YEAR, ptm->tm_year); + pkt_putword(pkthdr_buffer + PKTHDR_MONTH, ptm->tm_mon); + pkt_putword(pkthdr_buffer + PKTHDR_DAY, ptm->tm_mday); + pkt_putword(pkthdr_buffer + PKTHDR_HOUR, ptm->tm_hour); + pkt_putword(pkthdr_buffer + PKTHDR_MINUTE, ptm->tm_min); + pkt_putword(pkthdr_buffer + PKTHDR_SECOND, ptm->tm_sec); + pkt_putword(pkthdr_buffer + PKTHDR_BAUD, pkt->baud); + pkt_putword(pkthdr_buffer + PKTHDR_PKTTYPE, 0x0002); + pkt_putword(pkthdr_buffer + PKTHDR_ORIGNET, pkt->orig.net); + pkt_putword(pkthdr_buffer + PKTHDR_DESTNET, pkt->dest.net); + pkt_putbyte(pkthdr_buffer + PKTHDR_PRODCODELOW, 0xfe); + pkt_putword(pkthdr_buffer + PKTHDR_REVMAJOR, 0); + memcpy(pkthdr_buffer + PKTHDR_PASSWORD, pkt->password, MIN(8, strlen(pkt->password))); + pkt_putword(pkthdr_buffer + PKTHDR_QORIGZONE, pkt->orig.zone); + pkt_putword(pkthdr_buffer + PKTHDR_QDESTZONE, pkt->dest.zone); + /* .. skipped .. */ + pkt_putword(pkthdr_buffer + PKTHDR_ORIGZONE, pkt->orig.zone); + pkt_putword(pkthdr_buffer + PKTHDR_DESTZONE, pkt->dest.zone); + pkt_putword(pkthdr_buffer + PKTHDR_ORIGPOINT, pkt->orig.point); + pkt_putword(pkthdr_buffer + PKTHDR_DESTPOINT, pkt->dest.point); + + return pkthdr_buffer; +} + +static char *pkt_putmsgheader(char *msghdr_buffer, const s_message *msg) +{ + char buf[30]; + + memset(msghdr_buffer, '\0', PKTMSGHDR_SIZE); + + pkt_putword(msghdr_buffer + PKTMSGHDR_PKTTYPE, 0x0002); + pkt_putword(msghdr_buffer + PKTMSGHDR_ORIGNODE, msg->orig.node); + pkt_putword(msghdr_buffer + PKTMSGHDR_DESTNODE, msg->dest.node); + pkt_putword(msghdr_buffer + PKTMSGHDR_ORIGNET, msg->orig.net); + pkt_putword(msghdr_buffer + PKTMSGHDR_DESTNET, msg->dest.net); + pkt_putword(msghdr_buffer + PKTMSGHDR_ATTR, msg->attr & MSGATTR_NOTZEROED); + pkt_putword(msghdr_buffer + PKTMSGHDR_COST, msg->cost); + strnxcpy(msghdr_buffer + PKTMSGHDR_DATE, time_string_msghdr(buf, msg->time), 20); + strnxcpy(msghdr_buffer + PKTMSGHDR_TOUSER, msg->nameto, 36); + strnxcpy(msghdr_buffer + PKTMSGHDR_FROMUSER, msg->namefrom, 36); + strnxcpy(msghdr_buffer + PKTMSGHDR_SUBJECT, msg->subject, 72); + + return msghdr_buffer; +} + +static int pkt_writepacket(FILE *fp, const s_packet *pkt) +{ + int i; + char pkthdr[PKTHDR_SIZE]; + char msghdr[PKTMSGHDR_SIZE]; + + pkt_putpktheader(pkthdr, pkt); + + if( fwrite(pkthdr, sizeof(pkthdr), 1, fp) != 1 ) + return 1; + + for( i = 0; i < pkt->n_msgs; i++ ) + { + pkt_putmsgheader(msghdr, &pkt->msgs[i]); + + if( fwrite(msghdr, sizeof(msghdr), 1, fp) != 1 ) + return 1; + + if( pkt->msgs[i].text ) + fprintf(fp, "%s\r", pkt->msgs[i].text); + + if( pkt->msgs[i].tagline ) + fprintf(fp, "... %s\r", pkt->msgs[i].tagline); + + fprintf(fp, "--- %s\r", + pkt->msgs[i].tearline ? pkt->msgs[i].tearline : BF_BANNERVER); + + if( pkt->msgs[i].origin ) + fprintf(fp, "* Origin: %s\r", pkt->msgs[i].origin); + + fputc('\0', fp); /* end of message */ + } + + fputc('\0', fp); /* end of packet */ + fputc('\0', fp); /* end of packet */ + + return 0; +} + +int pkt_createpacket(const char *pktname, const s_packet *pkt) +{ + int rc; + FILE *fp; + + if( (fp = file_open(pktname, "w")) == NULL ) + return -1; + + rc = pkt_writepacket(fp, pkt); + + if( file_close(fp) ) + return -1; + + return rc; +} diff --git a/source/bforce/u_plock.c b/source/bforce/u_plock.c new file mode 100644 index 0000000..5af27b6 --- /dev/null +++ b/source/bforce/u_plock.c @@ -0,0 +1,203 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "outbound.h" + +pid_t plock_read(const char *lockname) +{ + FILE *fp = NULL; + pid_t pid = 0; + + ASSERT(lockname != NULL); + + if( (fp = file_open(lockname, "rt")) ) + { + if( fscanf(fp, "%d", &pid) != 1 ) + pid = 0; + file_close(fp); + } + + DEB((D_OUTBOUND, "plock_read: file \"%s\", PID = %d", lockname, pid)); + + return pid; +} + +pid_t plock_write(const char *lockname) +{ + int fd, rc = PLOCK_OK; + char buf[32]; + + ASSERT(lockname != NULL); + + if( (fd = open(lockname, O_CREAT | O_RDWR, 0644)) < 0 ) + /* Don't log any errors, really we can have + * no outbound directory for this address */ + return PLOCK_ERROR; + + chmod(lockname, 0644); + + sprintf(buf, "%10d\n", (int)getpid()); + + if( write(fd, (char *)buf, strlen(buf)) != strlen(buf) ) + { + logerr("can't write PID to the lock file \"%s\"", lockname); + rc = PLOCK_ERROR; + } + + close(fd); + + if( rc != PLOCK_OK ) + unlink(lockname); + + return rc; +} + +/* + * Return codes: + * PLOCK_OK + * PLOCK_EXIST + * PLOCK_ERROR + * PLOCK_OURBSY + */ +int plock_check(const char *lockname) +{ + pid_t pid = 0; + struct stat st; + + ASSERT(lockname != NULL); + + if( stat(lockname, &st) && errno == ENOENT ) + return PLOCK_OK; + + if( (pid = plock_read(lockname)) == 0 ) + return (errno == ENOENT) ? PLOCK_OK : PLOCK_ERROR; + + if( pid == getpid() ) + return PLOCK_OURLOCK; /* Should we unlink it? */ + + if( kill(pid, 0) == -1 && errno == ESRCH ) + { + /* + * That process no longer exists, + * try to remove lock file + */ + log("remove stale lock file \"%s\", PID %d", + lockname, (int)pid); + + if( !unlink(lockname) ) + return PLOCK_OK; + else + { + logerr("cannot remove lock file"); + return PLOCK_ERROR; + } + } + + return PLOCK_EXIST; /* locking process still lives */ +} + +int plock_link(const char *lockname, const char *tmpname) +{ + int rc; + + ASSERT(lockname != NULL && tmpname != NULL); + + if( !link(tmpname, lockname) ) + { + unlink(tmpname); + return PLOCK_OK; + } + + /* Can't create link */ + if( errno == EEXIST ) + { + if( (rc = plock_check(lockname)) != PLOCK_OK ) + { + if( rc == PLOCK_OURLOCK ) + rc = PLOCK_OK; + } + else if( link(tmpname, lockname) ) + { + logerr("cannot link lock \"%s\" to \"%s\"", tmpname, lockname); + rc = PLOCK_ERROR; + } else + rc = PLOCK_OK; + } + else + { + logerr("cannot link lock \"%s\" to \"%s\"", tmpname, lockname); + rc = PLOCK_ERROR; + } + + if( unlink(tmpname) == -1 && errno != ENOENT ) + logerr("cannot remove lock file \"%s\"", tmpname); + + return rc; +} + +int plock_create(const char *lockname) +{ + int rc; + char *tmpname, *p; + + ASSERT(lockname != NULL); + + tmpname = xstrcpy(lockname); + if( (p = strrchr(tmpname, DIRSEPCHR)) && p != tmpname ) + *++p = '\0'; + else + { + free(tmpname); + return PLOCK_ERROR; + } + tmpname = xstrcat(tmpname, "bforce-XXXXXX"); + + if( (p = mktemp(tmpname)) == NULL ) + { + logerr("can't generate unique file name from \"%s\"", tmpname); + free(tmpname); + return PLOCK_ERROR; + } + + if( (rc = plock_write(p)) == PLOCK_OK ) + rc = plock_link(lockname, p); + + DEB((D_OUTBOUND, "out_bsy_createfile: createlink(\"%s\", \"%s\"), rc = %d", + lockname, p, rc)); + + free(tmpname); + + return rc; +} + +int plock_remove(const char *lockname) +{ + pid_t pid = 0; + + ASSERT(lockname != NULL); + + DEB((D_OUTBOUND, "out_bsy_unlinkfile: want unlink \"%s\"", lockname)); + + if( (pid = plock_read(lockname)) == 0 ) + return 1; + + if( pid == getpid() && unlink(lockname) == -1 ) + return 1; + + return 0; +} + diff --git a/source/bforce/u_recode.c b/source/bforce/u_recode.c new file mode 100644 index 0000000..1a9e0ac --- /dev/null +++ b/source/bforce/u_recode.c @@ -0,0 +1,141 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +char default_table[RECODE_MAX_CHAR+1] = + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" + "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" + "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" + "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" + "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" + "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" + "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" + "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" + "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" + "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"; + +s_recode_table recode_table_in; +s_recode_table recode_table_out; +bool initialised = FALSE; + +static void recode_init(void) +{ + memset(&recode_table_in, '\0', sizeof(s_recode_table)); + memset(&recode_table_out, '\0', sizeof(s_recode_table)); + + memcpy(recode_table_in.table, default_table, sizeof(default_table)); + memcpy(recode_table_out.table, default_table, sizeof(default_table)); +} + +static int recode_load_table(char *dest, const char *filename) +{ + FILE *fp; + char buf[80]; + int find = 0; + int repl = 0; + int line = 0; + + /* Restore default recode table */ + memcpy(dest, default_table, sizeof(default_table)); + + fp = file_open(filename, "r"); + if( !fp ) + { + logerr("cannot open recode table \"%s\"", filename); + return -1; + } + + while( fgets(buf, sizeof(buf), fp) ) + { + ++line; + string_chomp(buf); + string_trimboth(buf); + + if( *buf == '#' ) + continue; + + if( sscanf(buf, "%i %i", &find, &repl) == 2 ) + { + if( 0 > find || find > RECODE_MAX_CHAR ) + log("recode character out of range 0..%d in \"%s\" line %d", + RECODE_MAX_CHAR, filename, line); + else + dest[find] = (unsigned char)repl; + } + } + + file_close(fp); + + return 0; +} + +static int recode_update_table(s_recode_table *tab, const char *filename) +{ + bool newtab = FALSE; + + /* + * Check/update current recode table + */ + if( filename && *filename ) + { + if( !tab->filename || strcmp(filename, tab->filename) ) + newtab = TRUE; + } + else if( tab->filename && *tab->filename ) + newtab = TRUE; + + if( newtab ) + { + if( filename && *filename ) + { + tab->filename = filename; + recode_load_table(tab->table, filename); + } + else + { + tab->filename = NULL; + memcpy(tab->table, default_table, sizeof(default_table)); + } + } + + return 0; +} + +char *recode(char *str, s_recode_table *tab, const char *filename) +{ + char *p; + + if( !initialised ) + { + recode_init(); + initialised = TRUE; + } + + recode_update_table(tab, filename); + + for( p = str; *p; p++ ) + *p = tab->table[(unsigned char)*p]; + + return str; +} + diff --git a/source/bforce/u_string.c b/source/bforce/u_string.c new file mode 100644 index 0000000..0dedde9 --- /dev/null +++ b/source/bforce/u_string.c @@ -0,0 +1,932 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef TEST +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#else +#include +#include +#define TRUE 1 +#define FALSE 0 +#define bool int +#define xmalloc malloc +#define xrealloc realloc +#define ASSERT +#endif + +/* + * Maximum number of quoted-printable strings we will store together + */ +#define PRINTABLE_MAXITEMS 5 + +/* + * Cyclic buffer for quoted-printable strings + */ +static char *printable_storage[PRINTABLE_MAXITEMS]; + +/* + * Position of next entry to use in printable_storage[] + */ +static int printable_pos = -1; + + +/***************************************************************************** + * Allocate memory for the copy of a string pointed by src + * + * Arguments: + * src pointer to the null-terminated string + * + * Return value: + * Pointer to the resulting string (must be freed) + */ +char *xstrcpy(const char *src) +{ + char *tmp; + + if( !src ) + return NULL; + + tmp = xmalloc(strlen(src)+1); + strcpy(tmp, src); + + return tmp; +} + +/***************************************************************************** + * Append string pointed by add to the string src, allocate memory for result + * + * Arguments: + * src pointer to the null-terminated string (will be freed) + * add this one will be appended to the src + * + * Return value: + * Pointer to the resulting string (must be freed) + */ +char *xstrcat(char *src, const char *add) +{ + char *tmp; + size_t size; + + if( !add || *add == '\0' ) + return src; + + size = (src ? strlen(src) : 0) + strlen(add); + tmp = (char*)xmalloc(size+1); + + if( src ) + { + strcpy(tmp, src); + free(src); + } else + *tmp = '\0'; + + strcat(tmp, add); + + return tmp; +} + +/***************************************************************************** + * Copy a string to the buffer. Checks for the destination buffer overflow and + * terminating '\0' character. + * + * Arguments: + * dst pointer to the destination buffer + * src string to copy from + * len destination buffer size + * + * Return value: + * Pointer to the resulting string + */ +char *strnxcpy(char *dst, const char *src, size_t len) +{ + ASSERT(src != NULL && dst != NULL && len >= 0); + + dst[len - 1] = 0; + + return strncpy(dst, src, len - 1); +} + +/***************************************************************************** + * Add one string to the end of another. Checks for destination buffer + * overflow and terminating '\0' character. + * + * Arguments: + * dst pointer to the destination buffer (append to the string + * stored in it) + * src append this string + * len destination buffer size + * + * Return value: + * Pointer to the resulting string + */ +char *strnxcat(char *dst, const char *src, size_t len) +{ + int pos; + + ASSERT(src != NULL && dst != NULL && len >= 0); + + pos = strlen(dst); + + return strnxcpy(dst + pos, src, len - pos); +} + +/***************************************************************************** + * Get next substring from the string. + * + * Arguments: + * str pointer to a null-terminated string + * next points to the pointer where you want store address of + * the next substring for next calls + * delim delimiter characters, if NULL than the isspace() call used + * to check for the delimiter characters + * quoted ignore spaces in the quoted substrings + * + * Return value: + * Pointer to the new substring or NULL if no more available + */ +char *string_token(char *str, char **next, const char *delim, int quoted) +{ + char *yield; + char *p; + + ASSERT(next != NULL); + + yield = str ? str : *next; + + if( yield ) + { + if( delim && *delim ) + while( *yield && strchr(delim, *yield) ) yield++; + else + while( isspace(*yield) ) yield++; + + if( *yield ) + { + if( quoted && *yield == '"' ) + { + p = ++yield; + while( *p && *p != '"' ) p++; + } + else + { + p = yield; + if( delim && *delim ) + while( *p && !strchr(delim, *p) ) p++; + else + while( *p && !isspace(*p) ) p++; + } + if( *p ) + { + *p = '\0'; + *next = p+1; + } else + *next = NULL; + } else + yield = *next = NULL; + } + + return yield; +} + +/***************************************************************************** + * Remove trailing CR and LF characters + * + * Arguments: + * str pointer to the null-terminated string + * + * Return value: + * Pointer to the string + */ +char *string_chomp(char *str) +{ + char *p; + + ASSERT(str != NULL); + + if( str && *str ) + { + p = str + strlen(str + 1); + if( *p == '\n' ) + *p-- = '\0'; + if( *p == '\r' && p >= str ) + *p = '\0'; + } + + return str; +} + +/***************************************************************************** + * Find the firtst occurance of substring into the string + * + * Arguments: + * substr pointer to the null-terminated substring + * string pointer to the null-terminated string + * + * Return value: + * Pointer to the first occurrence of the substring in the string, + * and NULL if substring is not found + */ +const char *string_casestr(const char *string, const char *substr) +{ + size_t subln = strlen(substr); + size_t strln = strlen(string); + + while( *string && strln >= subln ) + { + if( !strncasecmp(substr, string, subln) ) + return string; + + ++string; + --strln; + } + + return NULL; +} + +/***************************************************************************** + * Find character in the string (It is like strchr(), but case insensitive) + * + * Arguments: + * str pointer to the null-terminated string + * ch character you want to find + * + * Return value: + * Pointer to the first occurrence of the character in the string, + * and NULL if character is not found + */ +const char *string_casechr(const char *str, int ch) +{ + ch = tolower(ch); + + while( *str ) + { + if( tolower(*str) == ch ) + return str; + + ++str; + } + + return NULL; +} + +/***************************************************************************** + * Convert string to the upper case + * + * Arguments: + * str pointer to the null-terminated string + * + * Return value: + * Pointer to the string + */ +char *string_toupper(char *str) +{ + char *p; + + ASSERT(str != NULL); + + for( p = str; *p; p++ ) *p = toupper(*p); + + return(str); +} + +/***************************************************************************** + * Convert string to the lower case + * + * Arguments: + * str pointer to the null-terminated string + * + * Return value: + * Pointer to the string + */ +char *string_tolower(char *str) +{ + char *p; + + ASSERT(str != NULL); + + for( p = str; *p; p++ ) *p = tolower(*p); + + return(str); +} + +/***************************************************************************** + * Check wheather string doesn't contain lower case characters + * + * Arguments: + * str pointer to the null-terminated string + * + * Return value: + * Return TRUE if string conforms our requirements, and FALSE if not + */ +bool string_isupper(const char *str) +{ + const char *p; + + ASSERT(str != NULL); + + for( p = str; *p; p++ ) + { + if( isalpha(*p) && islower(*p) ) break; + } + + return (*p == '\0') ? TRUE : FALSE; +} + +/***************************************************************************** + * Check wheather string doesn't contain upper case characters + * + * Arguments: + * str pointer to the null-terminated string + * + * Return value: + * Return TRUE if string conforms our requirements, and FALSE if not + */ +bool string_islower(const char *str) +{ + const char *p; + + ASSERT(str != NULL); + + for( p = str; *p; p++ ) + { + if( isalpha(*p) && isupper(*p) ) break; + } + + return (*p == '\0') ? TRUE : FALSE; +} + +/***************************************************************************** + * Remove spaces at the end of string + * + * Arguments: + * str pointer to the null-terminated string + * + * Return value: + * Pointer to the string + */ +char *string_trimright(char *str) +{ + char *p; + + ASSERT(str != NULL); + + if( str && *str ) + { + p = str + strlen(str+1); + while( p >= str && isspace(*p) ) *p-- = '\0'; + } + + return str; +} + +/***************************************************************************** + * Remove spaces at the begining of string + * + * Arguments: + * str pointer to the null-terminated string + * + * Return value: + * pointer to the string + */ +char *string_trimleft(char *str) +{ + char *p; + + ASSERT(str != NULL); + + if( str && *str ) + { + p = str; + while( isspace(*p) ) p++; + if( p > str ) + memmove(str, p, strlen(p)+1); + } + + return str; +} + +/***************************************************************************** + * Remove white spaces at the begining and at the end of string + * + * Arguments: + * str pointer to the null-terminated string + * + * Return value: + * pointer to the string + */ +char *string_trimboth(char *str) +{ + char *p; + + ASSERT(str != NULL); + + if( str && *str ) + { + /* Remove leading spaces */ + p = str; + while( isspace(*p) ) p++; + if( p > str ) + memmove(str, p, strlen(p)+1); + + /* Remove trailing spaces */ + p = str + strlen(str+1); + while( p >= str && isspace(*p) ) *p-- = '\0'; + } + + return str; +} + +/***************************************************************************** + * Quote all unprintable characters in the buffer (e.g. "\xff\xfe") + * + * Arguments: + * buffer pointer to the buffer to process + * buflen buffer size + * + * Return value: + * Pointer to the quoted-printable string (must be freed) + */ +char *string_printable_buffer(const char *buffer, size_t buflen) +{ + char *dest, *p; + const char *bp; + int nonprintcount = 0; + size_t pos = 0; + + for( bp = buffer, pos = 0; pos < buflen; bp++, pos++ ) + { + if( !isprint((unsigned char)*bp) ) + nonprintcount++; + } + + dest = xmalloc(buflen + nonprintcount * 4 + 1); + + if( nonprintcount == 0 ) + { + memcpy(dest, buffer, buflen); + dest[buflen] = '\0'; + } + else + { + p = dest; + for( pos = 0; pos < buflen; buffer++, pos++ ) + { + if( !isprint((unsigned char)*buffer) ) + { + sprintf(p, "\\x%02x", (unsigned char)*buffer); + p += 4; + } else + *p++ = *buffer; + } + *p = '\0'; + } + + return dest; +} + +/***************************************************************************** + * Quote all unprintable characters in the string (e.g. "\xff\xfe") + * + * Arguments: + * str pointer to the null-terminated string + * + * Return value: + * Pointer to the quoted-printable string. Memory allocated for the + * resulting string will be freed automatically. So don't use more + * than last PRINTABLE_MAXITEMS pointers returned by this function. + */ +const char *string_printable(const char *str) +{ + char *p; + const char *q; + int nonprintcount = 0; + size_t pos = 0; + size_t len = 0; + + if( printable_pos == -1 ) + { + memset(printable_storage, '\0', sizeof(printable_storage)); + printable_pos = 0; + } + + if( str == NULL ) return "(null)"; + + len = strlen(str); + + for( q = str, pos = 0; pos < len; q++, pos++ ) + { + if( iscntrl((unsigned char)*q) || !isprint((unsigned char)*q) ) + nonprintcount++; + } + + if( !nonprintcount ) + return str; + + if( printable_pos >= PRINTABLE_MAXITEMS ) + printable_pos = 0; + + if( printable_storage[printable_pos] ) + free(printable_storage[printable_pos]); + + p = printable_storage[printable_pos] = xmalloc(len + nonprintcount * 4 + 1); + + for( pos = 0; pos < len; str++, pos++ ) + { + if( iscntrl((unsigned char)*str) || !isprint((unsigned char)*str) ) + { + sprintf(p, "\\x%02x", (unsigned char)*str); + p += 4; + } else + *p++ = *str; + } + *p = '\0'; + + return printable_storage[printable_pos++]; +} + +/***************************************************************************** + * Replace all chracters 'oldchar' by the 'newchar' + * + * Arguments: + * str pointer to the null-terminated string + * oldchar old chracter + * newchar character to put istead of 'oldchar' + * + * Return value: + * Pointer to the string + */ +char *string_replchar(char *str, char oldchar, char newchar) +{ + char *p = str; + + while( *p ) + { + if( *p == oldchar ) *p = newchar; + ++p; + } + + return str; +} + +/***************************************************************************** + * Devide string on substrings and put pointers to them into the + * dest[] array. + * + * Arguments: + * dest destination array where we should put substrings + * items number of entries in dest[] + * str string to parse (will be destroyed) + * separator separator character + * + * Return value: + * Number of substrings in the dest[] + */ +int string_parse(char **dest, int items, char *str, int separator) +{ + int count = 0; + char *p = str; + + dest[count++] = str; + + while( *p && count < items ) + { + if( *((unsigned char *)p) == separator ) + { + *p++ = '\0'; + dest[count++] = p; + } else + ++p; + } + + return count; +} + +/***************************************************************************** + * Devide string on substrings separated by white-space characters and put + * pointers to them into the dest[] array. Also it will ignore spaces in + * quoted strings (quote characters will be removed) + * + * Arguments: + * dest destination array where we should put substrings + * items number of entries in dest[] + * str string to parse (will be destroyed) + * + * Return value: + * Number of substrings in the dest[] + */ +int string_parse_regular(char **dest, int items, char *str) +{ + int count = 0; + char *p = str; + + while( *p ) + { + while( *p && isspace(*p) ) + ++p; + + if( *((unsigned char *)p) == '"' && *++p ) + { + dest[count++] = p; + while( *p && *((unsigned char *)p) != '"' ) p++; + } + else if( *p ) + { + dest[count++] = p; + while( *p && !isspace(*p) ) p++; + } + + if( *p && count < items ) + *p++ = '\0'; + else + break; + } + + return count; +} + +/***************************************************************************** + * Replace all substrings 'find' by the 'repl' in the string 'str' + * + * Arguments: + * str null-terminated string to process (will be unchanged) + * find substring to find + * repl replace substring + * + * Return value: + * Pointer to the new string (must be freed) + */ +char *string_translate(const char *str, const char *find, const char *repl) +{ + size_t sz_find = strlen(find); + size_t sz_repl = strlen(repl); + size_t sz_dest = strlen(str); + char *dest, *p; + + p = dest = xstrcpy(str); + + if( !sz_find ) return dest; + + while( *p ) + { + if( memcmp(p, find, sz_find) == 0 ) + { + size_t offset = p - dest; + size_t newsize = sz_dest + (sz_repl - sz_find); + + if( newsize > sz_dest ) + dest = xrealloc(dest, newsize+1); + + if( sz_repl > sz_find ) + memmove(dest + offset + (sz_repl - sz_find), dest + offset, sz_dest - offset + 1); + else if( sz_repl < sz_find ) + memmove(dest + offset, dest + offset + (sz_find - sz_repl), sz_dest - offset + 1); + + memcpy(dest + offset, repl, sz_repl); + + sz_dest = newsize; + p = dest + offset + sz_repl; + } else + ++p; + } + + return dest; +} + +/***************************************************************************** + * Convert size into human readable format (e.g. 100,256Kb or 20.7Mb) + * + * Arguments: + * buffer pointer to the buffer for resulting string + * size size in bytes that you want to print + * + * Return value: + * Pointer to the string + */ +char *string_humansize(char *buffer, size_t size) +{ + if( size < 1024 ) + sprintf(buffer, "%ldb", (long)size); + else if( size < 100*1024 ) + sprintf(buffer, "%.1fK", ((double)size)/1024.0); + else if( size < 1000*1024 ) + sprintf(buffer, "%ldK", (long)(size/1024)); + else if( size < 100*1024*1024 ) + sprintf(buffer, "%.1fM", ((double)size)/(1024.0*1024.0)); + else if( size < 1000*1024*1024 ) + sprintf(buffer, "%ldM", (long)(size/(1024*1024))); + else + sprintf(buffer, "%.1fG", ((double)size)/(1024.0*1024.0*1024.0)); + + return string_replchar(buffer, ',', '.'); +} + +/***************************************************************************** + * Interpret escape sequence (\xNN, \NNN, \r, \n, etc.) + * + * Arguments: + * pptr points a pointer to the first character after '\' + * + * Return value: + * Value of the escaped character + */ +int string_get_escape(char **pptr) +{ + int ch = 0; + static const char *hexdigits = "0123456789abcdef"; + char *p = *pptr; + + if( *p == 'x' ) + { + const char *q; + + if( (q = string_casechr(hexdigits, *(++p))) ) + { + ch = q - hexdigits; + if( (q = string_casechr(hexdigits, *(++p))) ) + { + ch = ch * 16 + (q - hexdigits); + } + } + } + else if( *p == '0' || *p == '1' || *p == '2' || *p == '3' ) + { + ch = *(p++) - '0'; + if( isdigit(*p) && *p != '8' && *p != '9' ) + { + ch = ch * 8 + (*(p++) - '0'); + if( isdigit(*p) && *p != '8' && *p != '9' ) + { + ch = ch * 8 + (*p - '0'); + } + } + } + else switch(*p) { + case 'a': + ch = '\a'; break; + case 'b': + ch = '\b'; break; + case 'f': + ch = '\f'; break; + case 'n': + ch = '\n'; break; + case 'r': + ch = '\r'; break; + case 't': + ch = '\t'; break; + case '\\': + ch = '\\'; break; + default: + ch = *p; + } + + *pptr = p + 1; + + return (ch > 0) ? (ch & 0xff) : -1; +} + +int string_dequote(char *dst, char *src) +{ + char *d = dst; + char *s = src; + int ch; + + while( *s ) + { + if( s[0] == '\\' && s[1] ) + { + ++s; + ch = string_get_escape(&s); + if( ch != -1 ) + *d++ = ch; + } + else + *d++ = *s++; + } + + *d = '\0'; + + return 0; +} + +char *string_concat(const char *str, ...) +{ + va_list args; + size_t yield_len; + char *yield_ptr; + char *yield; + char *p; + + /* + * Calculate total length of yielding string + */ + yield_len = strlen(str); + va_start(args, str); + while( (p = va_arg(args, char *)) ) + yield_len += strlen(p); + va_end(args); + + yield = xmalloc(yield_len + 1); + strncpy(yield, str, yield_len); + yield[yield_len] = '\0'; + yield_ptr = yield + strlen(yield); + + va_start(args, str); + while( (p = va_arg(args, char *)) ) + { + strcpy(yield_ptr, p); + yield_ptr += strlen(p); + } + va_end(args); + + return yield; +} + +void string_bin_to_hex(char *string, const char *binptr, int binlen) +{ + static const char *hexdigits = "0123456789abcdef"; + int i; + + for( i = 0; i < binlen; i++ ) + { + *string++ = hexdigits[(*binptr >> 4) & 0x0f]; + *string++ = hexdigits[(*binptr ) & 0x0f]; + ++binptr; + } + *string = '\0'; +} + +int string_hex_to_bin(char *binptr, const char *string) +{ + static const char *hexdigits = "0123456789abcdef"; + int len = (int)strlen(string); + int i, val; + const char *p; + char *dest = binptr; + + for( i = 0; 2*i < len; i++ ) + { + if( (p = string_casechr(hexdigits, *(string++))) ) + { + val = (int)(p - hexdigits); + if( (p = string_casechr(hexdigits, *(string++))) ) + { + val = val * 16 + (int)(p - hexdigits); + *dest++ = (unsigned char)(val & 0xff); + } + else + return 0; + } + else + return 0; + } + + return (int)(dest - binptr); +} + +bool string_is_empty(const char *string) +{ + const char *p; + + for( p = string; *p; p++ ) + if( !isspace((int)(unsigned char)*p) ) + return FALSE; + + return TRUE; +} + +#ifdef TEST +int main(void) +{ + char *hexstr = "0406ff2354124e6a9b2f6ed6ff00411287"; + char binbuf[64]; + int binlen; + char newhex[64]; + + /* + * string_hex_to_bin() and string_bin_to_hex() + */ + printf("*** Checking string_hex_to_bin() and string_bin_to_hex()\n"); + printf("Original string : \"%s\"\n", hexstr); + binlen = string_hex_to_bin(binbuf, hexstr); + string_bin_to_hex(newhex, binbuf, binlen); + printf("Resulting string : \"%s\"\n", newhex); + if( strcmp(hexstr, newhex) ) + printf("<<< ERROR!!! >>>\n"); + + return 0; +} +#endif /* TEST */ + diff --git a/source/bforce/u_time.c b/source/bforce/u_time.c new file mode 100644 index 0000000..e17438e --- /dev/null +++ b/source/bforce/u_time.c @@ -0,0 +1,621 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" + +static const char *months[] = +{ + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" +}; + +int time_settimer(time_t *timer, int value) +{ + *timer = time(NULL) + value; + + return 0; +} + +int time_timerout(time_t timer) +{ + if( timer > 0 && time(NULL) >= timer ) + return 1; + + return 0; +} + +int time_timeleft(time_t timer) +{ + if( timer > 0 ) + return MAX(time(NULL) - timer, 0); + + return 0; +} + +int time_elapsed(time_t since_time) +{ + if( since_time > 0 ) + { + int yield = time(NULL) - since_time; + return ( yield > 0 ) ? yield : 0; + } + + return 0; +} + +/***************************************************************************** + * Put time string into buffer, according to the format + * + * Arguments: + * buffer pointer to the destination buffer + * buflen buffer size + * fmt format string (`man strftime' for more information) + * t seconds since 1970.. you know.. + * + * Return value: + * Pointer to the resulting string + */ +char *time_string_format(char *buffer, size_t buflen, const char *fmt, time_t t) +{ + struct tm *tm; + + if( !t ) t = time(&t); + + tm = localtime(&t); + + if( strftime(buffer, buflen, fmt, tm) == 0 ) + { + strnxcpy(buffer, "invalid format", buflen); + } + + return buffer; +} + +/***************************************************************************** + * Put time string into buffer (time format depends on the locale settings). + * + * Arguments: + * buffer pointer to the destination buffer + * buflen buffer size + * t seconds since 1970.. you know.. + * + * Return value: + * Pointer to the resulting string + */ +char *time_string_long(char *buffer, size_t buflen, time_t t) +{ + char *sptr; + + if( !t ) time(&t); + + sptr = ctime(&t); + strnxcpy(buffer, sptr, buflen); + + return string_chomp(buffer); +} + +/***************************************************************************** + * Put time string into buffer (e.g. My birth day is "Aug 11 07:20:00"). + * + * Arguments: + * buffer pointer to the destination buffer + * buflen buffer size + * t seconds since 1970.. you know.. + * + * Return value: + * Pointer to the resulting string + */ +char *time_string_log(char *buffer, size_t buflen, time_t t) +{ + struct tm *ptm; + + ASSERT(buflen > 16); + + if( !t ) time(&t); + + ptm = localtime(&t); + sprintf(buffer, "%3s %02d %02d:%02d:%02d", + months[ptm->tm_mon], ptm->tm_mday, + ptm->tm_hour, ptm->tm_min, ptm->tm_sec); + + return buffer; +} + +/***************************************************************************** + * Put date+time string into buffer. Special format for netmail message + * headers. + * + * Arguments: + * buffer pointer to the destination buffer + * buflen buffer size + * t seconds since 1970.. you know.. + * + * Return value: + * Pointer to the resulting string + */ +char *time_string_msghdr(char *buffer, time_t t) +{ + struct tm *ptm; + + if( !t ) time(&t); + + ptm = localtime(&t); + sprintf(buffer, "%02d %3s %02d %02d:%02d:%02d", + ptm->tm_mday, months[ptm->tm_mon], + (ptm->tm_year < 100) ? ptm->tm_year : ptm->tm_year % 100, + ptm->tm_hour, ptm->tm_min, ptm->tm_sec); + + return buffer; +} + +/***************************************************************************** + * Get TimeZone for our location + * + * Arguments: + * + * Return value: + * Offset in minutes + */ +long time_gmtoffset(void) +{ + time_t tt = time(NULL); + struct tm local = *localtime(&tt); + struct tm gmt = *gmtime(&tt); + long tz = gmt.tm_yday - local.tm_yday; + + if( tz > 1 ) + tz = -24; + else if( tz < -1 ) + tz = 24; + else + tz *= 24; + + tz += gmt.tm_hour - local.tm_hour; + tz *= 60; + tz += gmt.tm_min - local.tm_min; + + return tz; +} + +/***************************************************************************** + * Get TimeZone for our location as pointer to the null terminated string + * + * Arguments: + * buffer pointer to the destination buffer (must be at least 6 bytes) + * + * Return value: + * Pointer to the resulting string (e.g. "+0400") + */ +char *time_string_gmtoffset(char *buffer) +{ + long tz = time_gmtoffset(); + char sign = (tz > 0)?'+':'-'; + int hour = tz/60; + int mint = tz%60; + + sprintf(buffer, "%c%02d%02d", sign, hour, mint); + + return buffer; +} + +/***************************************************************************** + * Get time in native format from seconds counter (e.g. "1:30:10") + * + * Arguments: + * buffer pointer to the destination buffer (must be at least 9 bytes) + * timer number of seconds + * + * Return value: + * Pointer to the resulting string + */ +char *time_string_timer(char *buffer, int timer) +{ + int hour, min, sec; + + hour = (timer/3600); + min = (timer%3600)/60; + sec = (timer%60); + + if( hour ) + sprintf(buffer, "%02d:%02d:%02d", (hour < 100) ? hour : 99, min, sec); + else + sprintf(buffer, "%02d:%02d", min, sec); + + return buffer; +} + +/***************************************************************************** + * Get approximate interval in native format (e.g. "1 day", "3 hours") + * + * Arguments: + * buffer pointer to the destination buffer (must be large enough) + * seconds time interval in seconds + * + * Return value: + * Pointer to the resulting string + */ +char *time_string_approx_interval(char *buffer, int seconds) +{ + if( seconds < 0 ) + strcpy(buffer, "error"); + else if( seconds == 0 ) + strcpy(buffer, "up-to-date"); + else if( seconds == 1 ) + strcpy(buffer, "1 second"); + else if( seconds < 60 ) + sprintf(buffer, "%d seconds", seconds); + else if( seconds < 120 ) + strcpy(buffer, "1 minute"); + else if( seconds < 3600 ) + sprintf(buffer, "%d minutes", seconds/60); + else if( seconds < 7200 ) + strcpy(buffer, "1 hour"); + else if( seconds < 86400 ) + sprintf(buffer, "%d hours", seconds/3600); + else if( seconds < 172800 ) + strcpy(buffer, "1 day"); + else if( seconds < 999*86400 ) + sprintf(buffer, "%d days", seconds/86400); + else + sprintf(buffer, "%d years", seconds/(366*86400)); + + return buffer; +} + +/***************************************************************************** + * Check time for conforming to the time interval specified by string + * + * Arguments: + * str pointer to the time interval string + * now time to check (most often it is current time) + * + * Return value: + * Zero value if time conforms, 1 if not, and -1 if specified time interval + * string is incorrect + */ +int time_check(const char *str, struct tm *now) +{ + int h1, h2, m1, m2, beg, end, cur, day; + bool dayok = FALSE; + bool timeok = FALSE; + + ASSERT(str != NULL && now != NULL); + + if( *str == '\0' ) return 1; + + if( strncasecmp(str, "Sun", 3) == 0 ) day = 0; + else if( strncasecmp(str, "Mon", 3) == 0 ) day = 1; + else if( strncasecmp(str, "Tue", 3) == 0 ) day = 2; + else if( strncasecmp(str, "Wed", 3) == 0 ) day = 3; + else if( strncasecmp(str, "Thu", 3) == 0 ) day = 4; + else if( strncasecmp(str, "Fri", 3) == 0 ) day = 5; + else if( strncasecmp(str, "Sat", 3) == 0 ) day = 6; + else if( strncasecmp(str, "Any", 3) == 0 ) day = -1; + else if( strncasecmp(str, "Wk", 2) == 0 ) day = -2; + else if( strncasecmp(str, "We", 2) == 0 ) day = -3; + else day = -4; + + if( day >= 0 ) + { + dayok = (now->tm_wday == day); + str += 3; + } + else + { + switch(day) { + case -3: + dayok = ( (now->tm_wday == 0) || (now->tm_wday == 6) ); + str += 2; + break; + case -2: + dayok = ( (now->tm_wday != 0) && (now->tm_wday != 6) ); + str += 2; + break; + case -1: + str += 3; + default: + dayok = TRUE; + } + } + + if( !dayok ) return 1; + + if( *str == '\0' ) + return (day == -4) ? -1 : 0; + + if( sscanf(str, "%02d:%02d-%02d:%02d", &h1, &m1, &h2, &m2) != 4 ) + return -1; + + cur = now->tm_hour*60 + now->tm_min; + beg = h1*60 + m1; + end = h2*60 + m2; + + if( end > beg ) + timeok = ( (cur >= beg) && (cur <= end) ); + else + timeok = ( (cur >= beg) || (cur <= end) ); + + DEB((D_INFO, "checktime: is %02d:%02d between %02d:%02d and %02d:%02d? %s!", + now->tm_hour,now->tm_min, h1, m1, h2, m2, timeok ? "Yes" : "No")); + + return !timeok; +} + +/***************************************************************************** + * Check time for conforming to the time intervals + * + * Arguments: + * timestr pointer to the time intervals string + * tim time to check (most often it is current time) + * + * Return value: + * Zero value if time conforms, 1 if not, and -1 if specified time interval + * string is incorrect + */ +int time_checkintervals(const char *timestr, struct tm *now) +{ + char *str, *p; + + ASSERT(timestr != NULL); + + str = xstrcpy(timestr); + + for( p = strtok(str, ","); p; p = strtok(NULL, ",") ) + { + if( *p ) + { + switch(time_check(p, now)) { + case 0: + return 0; + case -1: + return -1; + case 1: + break; + default: + ASSERT(0); + } + } + } + + return 1; +} + +int timevec_add(s_timevec *dest, int day_beg, int day_end, long beg, long end) +{ + int i; + + /* + * Check for dupes. TODO: more complex checks + */ + for( i = 0; i < dest->num; i++ ) + { + if( dest->tvec[i].day_beg <= day_beg + && dest->tvec[i].day_end >= day_end + && dest->tvec[i].beg == beg + && dest->tvec[i].end == end ) + return 0; + } + + if( dest->num >= TIMEVEC_MAX_ELEMENTS ) + return -1; + + dest->tvec[dest->num].day_beg = day_beg; + dest->tvec[dest->num].day_end = day_end; + dest->tvec[dest->num].beg = beg; + dest->tvec[dest->num].end = end; + dest->num++; + + return 0; +} + +/***************************************************************************** + * Parse one time interval. Only uucico like time format is supported yet. + * + * Arguments: + * dest pointer to the destination time storage structure + * str time string to parse + * + * Return value: + * Zero value on success, and -1 for incorrect time strings + */ +int timevec_parse(s_timevec *dest, const char *str) +{ + int beg_hour = 0; + int end_hour = 0; + int beg_min = 0; + int end_min = 0; + enum day beg_day; + enum day end_day; + int beg = 0; + int end = 0; + + if( strncasecmp(str, "Sun", 3) == 0 ) + beg_day = DAY_SUNDAY; + else if( strncasecmp(str, "Mon", 3) == 0 ) + beg_day = DAY_MONDAY; + else if( strncasecmp(str, "Tue", 3) == 0 ) + beg_day = DAY_TUESDAY; + else if( strncasecmp(str, "Wed", 3) == 0 ) + beg_day = DAY_WEDNESDAY; + else if( strncasecmp(str, "Thu", 3) == 0 ) + beg_day = DAY_THURSDAY; + else if( strncasecmp(str, "Fri", 3) == 0 ) + beg_day = DAY_FRIDAY; + else if( strncasecmp(str, "Sat", 3) == 0 ) + beg_day = DAY_SATURDAY; + else if( strncasecmp(str, "Any", 3) == 0 ) + beg_day = DAY_ANY; + else if( strncasecmp(str, "Wk", 2) == 0 ) + beg_day = DAY_WORKDAY; + else if( strncasecmp(str, "We", 2) == 0 ) + beg_day = DAY_WEEKEND; + else + beg_day = DAY_UNDEF; + + end_day = beg_day; + + if( beg_day >= DAY_MONDAY && beg_day <= DAY_SUNDAY ) + str += 3; + else if( beg_day == DAY_ANY ) + str += 3; + else if( beg_day == DAY_WORKDAY || beg_day == DAY_WEEKEND ) + str += 2; + + if( sscanf(str, "%02d:%02d-%02d:%02d", &beg_hour, &beg_min, &end_hour, &end_min) != 4 ) + return -1; + + beg = beg_hour * 60 + beg_min; + end = end_hour * 60 + end_min; + + if( beg == end ) + return -1; + + switch(beg_day) { + case DAY_MONDAY: + case DAY_TUESDAY: + case DAY_WEDNESDAY: + case DAY_THURSDAY: + case DAY_FRIDAY: + case DAY_SATURDAY: + case DAY_SUNDAY: + timevec_add(dest, beg_day, end_day, beg, end); + break; + case DAY_WORKDAY: + timevec_add(dest, DAY_MONDAY, DAY_FRIDAY, beg, end); + break; + case DAY_WEEKEND: + timevec_add(dest, DAY_SATURDAY, DAY_SUNDAY, beg, end); + break; + default: + timevec_add(dest, DAY_MONDAY, DAY_SUNDAY, beg, end); + break; + } + + return 0; +} + +int timevec_parse_list(s_timevec *dest, const char *str) +{ + char *p = NULL; + char *tmp = xstrcpy(str); + int rc = 0; + + for( p = strtok(tmp, ","); p; p = strtok(NULL, ",") ) + { + if( *p && timevec_parse(dest, p) == -1 ) + rc = -1; + } + + free(tmp); + + return rc; +} + +int timevec_check(const s_timevec *tv, const struct tm *now) +{ + int i; + bool ok = FALSE; + int cur = now->tm_hour * 60 + now->tm_min; + int cur_day = DAY_UNDEF; + + if( now->tm_wday == 0 ) + cur_day = DAY_SUNDAY; + else if( now->tm_wday == 1 ) + cur_day = DAY_MONDAY; + else if( now->tm_wday == 2 ) + cur_day = DAY_TUESDAY; + else if( now->tm_wday == 3 ) + cur_day = DAY_WEDNESDAY; + else if( now->tm_wday == 4 ) + cur_day = DAY_THURSDAY; + else if( now->tm_wday == 5 ) + cur_day = DAY_FRIDAY; + else if( now->tm_wday == 6 ) + cur_day = DAY_SATURDAY; + else + { + log("timevec_check: error 'tm->tm_wday' is out of range"); + return -1; + } + + for( i = 0; i < tv->num; i++ ) + { + if( (cur_day >= tv->tvec[i].day_beg) + && (cur_day <= tv->tvec[i].day_end) ) + { + int beg = tv->tvec[i].beg; + int end = tv->tvec[i].end; + + if( end > beg ) + ok = ( (cur >= beg) && (cur <= end) ); + else + ok = ( (cur >= beg) || (cur <= end) ); + + if( ok ) break; + } + } + + return ok ? 0 : 1; +} + +char *timevec_string(char *buffer, const s_timevec *tv, size_t buflen) +{ + int i; + char *ptr = buffer; + + *ptr = '\0'; + + for( i = 0; i < tv->num; i++ ) + { + if( tv->tvec[i].day_beg == DAY_MONDAY + && tv->tvec[i].day_end == DAY_SUNDAY ) + { + sprintf(ptr, "%02ld:%02ld-%02ld:%02ld,", + tv->tvec[i].beg / 60, tv->tvec[i].beg % 60, + tv->tvec[i].end / 60, tv->tvec[i].end % 60); + } + else if( tv->tvec[i].day_beg == tv->tvec[i].day_end ) + { + sprintf(ptr, "%d.%02ld:%02ld-%02ld:%02ld,", tv->tvec[i].day_beg, + tv->tvec[i].beg / 60, tv->tvec[i].beg % 60, + tv->tvec[i].end / 60, tv->tvec[i].end % 60); + } + else + { + sprintf(ptr, "%d.%02ld:%02ld-%d.%02ld:%02ld,", + tv->tvec[i].day_beg, tv->tvec[i].beg / 60, tv->tvec[i].beg % 60, + tv->tvec[i].day_end, tv->tvec[i].end / 60, tv->tvec[i].end % 60); + } + + ptr += strlen(ptr); + } + + if( ptr > buffer ) + *(ptr - 1) = '\0'; + + return buffer; +} + +bool timevec_isdefined(const s_timevec *tv) +{ + return tv->num ? TRUE : FALSE; +} + +bool timevec_isnow(const s_timevec *tv, const struct tm *now) +{ + return ( timevec_check(tv, now) == 0 ) ? TRUE : FALSE; +} + +/* end of u_time.c */ diff --git a/source/bfutil/bfindex.c b/source/bfutil/bfindex.c new file mode 100644 index 0000000..13158bd --- /dev/null +++ b/source/bfutil/bfindex.c @@ -0,0 +1,286 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "version.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" + +/* + * Our fake expressions checker. Allways return FALSE (?) + */ +bool eventexpr(s_expr *expr) +{ + return FALSE; +} + +static void usage(void) +{ + printf_usage("nodelist compiler", + "usage: bfindex [-fh]\n" + "\n" + "options:\n" + " -f force nodelist compiling\n" + " -h show this help message\n" + "\n" + ); +} + +static int nodelist_makeindex(s_nodelist *nlp, s_faddr addr) +{ + s_bni bni; + char buf[1024]; + long countnodes = 0L; + long countlines = 0L; + enum nodelist_keyword keyword; + + memset(&bni, 0, sizeof(s_bni)); + bni.zone = addr.zone; + bni.net = addr.net; + bni.node = addr.node; + bni.point = addr.point; + + if( nodelist_createheader(nlp) == -1 ) + { + log("cannot create nodelist index header"); + return -1; + } + + while(1) + { + char *p, *q; + + if( (bni.offset = ftell(nlp->fp_nodelist)) == -1 ) + { + logerr("ftell() return -1 for nodelist"); + return -1; + } + + if( fgets(buf, sizeof(buf), nlp->fp_nodelist) == NULL ) + { + return countnodes; + } + + string_chomp(buf); + ++countlines; + + if( buf[0] == ';' || buf[0] == '\0' ) continue; + + if( (p = strchr(buf, ',')) ) + { + *p++ = '\0'; + if( (q = strchr(p, ',')) ) *q = '\0'; + } + + if( p == NULL || *p == '\0' ) + { + log("incorrect nodelist line %ld: Short line", countlines); + continue; + } + + if( (keyword = nodelist_keywordval(buf)) == -1 ) + { + log("incorrect nodelist line %d: Bad keyword \"%s\"", + countlines, buf); + continue; + } + + if( keyword == KEYWORD_BOSS ) + { + s_faddr tmpaddr; + + if( ftn_addrparse(&tmpaddr, p, FALSE) ) + { + log("incorrect nodelist line %ld: Bad boss address \"%s\"", + countlines, p); + } + else + { + bni.zone = tmpaddr.zone; + bni.net = tmpaddr.net; + bni.node = tmpaddr.node; + bni.point = 0; + bni.hub = 0; + } + } + else if( ISDEC(p) ) + { + int value = atoi(p); + + if( value > 0x7fff ) + value = 0x7fff; + else if( value < 0 ) + value = 0; + + switch(keyword) { + case KEYWORD_ZONE: + bni.zone = value; + bni.net = 0; + bni.node = 0; + bni.point = 0; + bni.hub = 0; + break; + case KEYWORD_REGION: + bni.net = value; + bni.node = 0; + bni.point = 0; + bni.hub = 0; + break; + case KEYWORD_HOST: + bni.net = value; + bni.node = 0; + bni.point = 0; + bni.hub = 0; + break; + case KEYWORD_HUB: + bni.node = value; + bni.point = 0; + bni.hub = value; + break; + case KEYWORD_EMPTY: + case KEYWORD_PVT: + case KEYWORD_HOLD: + case KEYWORD_DOWN: + bni.node = value; + bni.point = 0; + break; + case KEYWORD_POINT: + bni.point = value; + break; + default: + ASSERT_MSG(); + } + + if( nodelist_putindex(nlp, &bni) == -1 ) + return -1; + + ++countnodes; + } + else + { + log("incorrect nodelist line %ld: Bad number \"%s\"", + countlines, p); + } + } + + return -1; +} + +int main(int argc, char *argv[]) +{ + s_cval_entry *cfptr; + char *nodelistdir = NULL; + time_t starttime = 0L; + bool forcecompile = FALSE; + long countnodes = 0L; + char c; + + /* Initialise random number generation */ + (void)srand((unsigned)time(0)); + /* Initialise current locale */ + (void)setlocale(LC_ALL, ""); + /* Set our name (for logging only) */ + + while( (c = getopt(argc, argv, "hf")) != EOF ) + { + switch( c ) { + case 'f': + forcecompile = TRUE; + break; + case 'h': + usage(); + exit(0); + default: + usage(); + exit(1); + } + } + + if( conf_readconf(conf_getconfname(), 0) ) + { + exit(1); + } + + if( log_open(log_getfilename(LOG_FILE_SESSION), NULL, NULL) ) + { + log("can't continue without logging"); + exit(1); + } + + /* Ignore some terminating signals */ + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + + time(&starttime); + + nodelistdir = conf_string(cf_nodelist_directory); + + for( cfptr = conf_first(cf_nodelist); cfptr; cfptr = conf_next(cfptr) ) + { + s_nodelist *nlp = NULL; + bool willcompile = FALSE; + + if( forcecompile ) + { + willcompile = TRUE; + } + else if( (nlp = nodelist_open(nodelistdir, + cfptr->d.falist.what, + NODELIST_READ)) == NULL ) + { + willcompile = TRUE; + } + else + { + nodelist_close(nlp); nlp = NULL; + willcompile = FALSE; + } + + if( willcompile ) + { + log("rebuilding index for nodelist \"%s\"", cfptr->d.falist.what); + if( (nlp = nodelist_open(nodelistdir, cfptr->d.falist.what, + NODELIST_WRITE)) ) + { + long rc = nodelist_makeindex(nlp, cfptr->d.falist.addr); + nodelist_close(nlp); nlp = NULL; + if( rc > 0 ) countnodes += rc; + } + } + else + log("nodelist \"%s\" is up to date", cfptr->d.falist.what); + } + + if( countnodes > 0 ) + { + long ptime = (long)time(NULL) - (long)starttime; + long nps = (ptime > 0) ? countnodes / ptime : countnodes; + log("processed %ld nodes in %ld second(s) (%ld node/sec)", + countnodes, ptime, nps); + } + + deinit_conf(); + + /* + * Shutdown logging services + */ + if( log_isopened() ) log_close(); +#ifdef DEBUG + if( debug_isopened() ) debug_close(); +#endif + + exit(0); +} diff --git a/source/bfutil/bfstat.c b/source/bfutil/bfstat.c new file mode 100644 index 0000000..1d96522 --- /dev/null +++ b/source/bfutil/bfstat.c @@ -0,0 +1,338 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "version.h" +#include "logger.h" +#include "util.h" +#include "outbound.h" +#include "session.h" + +/* + * Command line options storage structure + */ +typedef struct { + bool calls_stat; + bool sort_bysize; + bool sort_byaddr; + bool sort_reverse; + bool disable_total_sizes; + bool humansizes; + int nodeslimit; +} s_opts; + + +/* + * Our fake expressions checker. Allways return FALSE (?) + */ +bool eventexpr(s_expr *expr) +{ + return FALSE; +} + +static void usage(void) +{ + printf_usage("outbound viewer", + "usage: bfstat [-afhprst] [-n]\n" + "\n" + "options:\n" + " -a sort by FTN address (default)\n" + " -c print incoming/outgoing calls statistic\n" + " -f disable queue sorting\n" + " -h print this help message\n" + " -n don't print more than systems\n" + " -p print sizes in human readable format\n" + " -r reverse order while sorting\n" + " -s sort by total files size\n" + " -t disable total sizes printing\n" + "\n" + ); +} + +static void bfstat_opts_default(s_opts *opts) +{ + memset(opts, '\0', sizeof(s_opts)); + + opts->sort_bysize = FALSE; + opts->sort_byaddr = TRUE; + opts->sort_reverse = FALSE; + opts->disable_total_sizes = FALSE; + opts->humansizes = FALSE; + opts->nodeslimit = 0; +} + +static void bfstat_print_outbound(s_sysqueue *queue, s_opts *opts) +{ + int i; + char sbuf[4][10]; + char age_buffer[20]; + char abuf[BF_MAXADDRSTR+1]; + size_t size_netmail = 0; + size_t size_arcmail = 0; + size_t size_other = 0; + time_t now = time(0); + int printnum = opts->nodeslimit ? MIN(opts->nodeslimit, queue->sysnum) + : queue->sysnum; + + printf("Address Netmail Arcmail Other Flavors Age\n"); + printf("=========================================================================\n"); + + for( i = 0; i < printnum; i++ ) + { + /* Update total size counters */ + if( !opts->disable_total_sizes ) + { + size_netmail += queue->systab[i].netmail_size; + size_arcmail += queue->systab[i].arcmail_size; + size_other += queue->systab[i].request_size + + queue->systab[i].files_size; + } + + /* Get mail age string */ + if( queue->systab[i].mailage > 0 ) + time_string_approx_interval(age_buffer, + (now - queue->systab[i].mailage)); + else + *age_buffer = '\0'; + + if( opts->humansizes ) + { + printf("%-25s %-9s %-9s %-9s %c%c%c%c%c %s\n", + ftn_addrstr(abuf, queue->systab[i].node.addr), + string_humansize(sbuf[0], queue->systab[i].netmail_size), + string_humansize(sbuf[1], queue->systab[i].arcmail_size), + string_humansize(sbuf[2], queue->systab[i].request_size + queue->systab[i].files_size), + (queue->systab[i].flavors & FLAVOR_HOLD ) ? 'H' : '.', + (queue->systab[i].flavors & FLAVOR_NORMAL) ? 'N' : '.', + (queue->systab[i].flavors & FLAVOR_DIRECT) ? 'D' : '.', + (queue->systab[i].flavors & FLAVOR_CRASH ) ? 'C' : '.', + (queue->systab[i].flavors & FLAVOR_IMMED ) ? 'I' : '.', + age_buffer); + } + else + { + printf("%-25s %-9ld %-9ld %-9ld %c%c%c%c%c %s\n", + ftn_addrstr(abuf, queue->systab[i].node.addr), + (long)(queue->systab[i].netmail_size), + (long)(queue->systab[i].arcmail_size), + (long)(queue->systab[i].request_size + queue->systab[i].files_size), + (queue->systab[i].flavors & FLAVOR_HOLD ) ? 'H' : '.', + (queue->systab[i].flavors & FLAVOR_NORMAL) ? 'N' : '.', + (queue->systab[i].flavors & FLAVOR_DIRECT) ? 'D' : '.', + (queue->systab[i].flavors & FLAVOR_CRASH ) ? 'C' : '.', + (queue->systab[i].flavors & FLAVOR_IMMED ) ? 'I' : '.', + age_buffer); + } + } + + if( !opts->disable_total_sizes ) + { + printf("=========================================================================\n"); + + if( opts->humansizes ) + { + printf("TOTAL %3d systems %-9s %-9s %-9s %-9s\n", + printnum, + string_humansize(sbuf[0], size_netmail), + string_humansize(sbuf[1], size_arcmail), + string_humansize(sbuf[2], size_other), + string_humansize(sbuf[3], size_netmail+size_arcmail+size_other)); + } + else + { + printf("TOTAL %3d systems %-9ld %-9ld %-9ld %-9ld\n", + printnum, + (long)size_netmail, (long)size_arcmail, (long)size_other, + (long)(size_netmail + size_arcmail + size_other)); + } + } +} + +static void bfstat_print_stat(s_sysqueue *queue, s_opts *opts) +{ + int i; + s_sess_stat stat; + char abuf[BF_MAXADDRSTR+1]; + time_t now = time(0); + int printnum = opts->nodeslimit ? MIN(opts->nodeslimit, queue->sysnum) + : queue->sysnum; + + printf("Address Last incoming Last outgoing Status\n"); + printf("=========================================================================\n"); + + for( i = 0; i < printnum; i++ ) + { + if( session_stat_get(&stat, &queue->systab[i].node.addr) ) + { + printf("%-25s No statistic available\n", + ftn_addrstr(abuf, queue->systab[i].node.addr)); + } + else + { + char last_in[30]; + char last_out[30]; + char status[60]; + char buffer[30]; + + /* + * Format date of the last successful incoming session + */ + if( stat.last_success_in > 0 ) + { + time_string_format(last_in, sizeof(last_in), + "%H:%M %d/%m/%y", stat.last_success_in); + } + else + strcpy(last_in, "--------------"); + + /* + * Format date of the last successful outgoing session + */ + if( stat.last_success_out > 0 ) + { + time_string_format(last_out, sizeof(last_out), + "%H:%M %d/%m/%y", stat.last_success_out); + } + else + strcpy(last_out, "--------------"); + + /* + * Generate calls status message + */ + if( stat.undialable ) + { + strcpy(status, "Undialable"); + } + else if( stat.hold_until > now ) + { + sprintf(status, "Holded for %s", + time_string_approx_interval(buffer, stat.hold_until - now)); + } + else if( stat.hold_freqs > now ) + { + sprintf(status, "Holded for %s", + time_string_approx_interval(buffer, stat.hold_freqs - now)); + } + else + strcpy(status, "Normal"); + + if( *status ) + { + printf("%-25s %-15s %-15s %s\n", + ftn_addrstr(abuf, queue->systab[i].node.addr), + last_in, last_out, status); + } + else + { + printf("%-25s %-15s %-15s\n", + ftn_addrstr(abuf, queue->systab[i].node.addr), + last_in, last_out); + } + } + } +} + +int main(int argc, char *argv[]) +{ + s_opts opts; + s_sysqueue queue; + s_outbound_callback_data ocb; + char c; + int i; + + bfstat_opts_default(&opts); + + while( (c = getopt(argc, argv, "acfhn:prst")) != EOF ) + { + switch( c ) { + case 'h': + usage(); + exit(0); + case 'c': + opts.calls_stat = TRUE; + break; + case 'f': + opts.sort_bysize = FALSE; + opts.sort_byaddr = FALSE; + opts.sort_reverse = FALSE; + break; + case 'p': + opts.humansizes = TRUE; + break; + case 't': + opts.disable_total_sizes = TRUE; + break; + case 'r': + opts.sort_reverse = TRUE; + break; + case 's': + opts.sort_byaddr = FALSE; + opts.sort_bysize = TRUE; + break; + case 'a': + opts.sort_byaddr = TRUE; + opts.sort_bysize = FALSE; + break; + case 'n': + if( ISDEC(optarg) ) + opts.nodeslimit = atoi(optarg); + break; + default: + usage(); + exit(1); + } + } + + memset(&queue, '\0', sizeof(s_sysqueue)); + + /* Initialise random number generation */ + (void)srand((unsigned)time(0)); + /* Initialise current locale */ + (void)setlocale(LC_ALL, ""); + + if( conf_readconf(conf_getconfname(), 0) ) + exit(1); + + memset(&ocb, '\0', sizeof(s_outbound_callback_data)); + ocb.callback = out_handle_sysqueue; + ocb.dest = (void *)&queue; + out_scan(&ocb, NULL); + + if( queue.sysnum > 1 && (opts.sort_byaddr || opts.sort_bysize) ) + { + int sort_opts = opts.sort_byaddr ? QUEUE_SORT_ADDRESS + : opts.sort_bysize ? QUEUE_SORT_SIZE : 0; + if( opts.sort_reverse ) + sort_opts |= QUEUE_SORT_REVERSE; + out_sysqueue_sort(&queue, sort_opts); + } + + if( queue.sysnum > 0 ) + { + if( opts.calls_stat ) + bfstat_print_stat(&queue, &opts); + else + bfstat_print_outbound(&queue, &opts); + } + else + printf("Outbound queue is empty\n"); + + fflush(stdout); + + deinit_sysqueue(&queue); + deinit_conf(); + + exit(0); +} + diff --git a/source/bfutil/nlookup.c b/source/bfutil/nlookup.c new file mode 100644 index 0000000..41445ce --- /dev/null +++ b/source/bfutil/nlookup.c @@ -0,0 +1,155 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#include "includes.h" +#include "confread.h" +#include "logger.h" +#include "util.h" +#include "nodelist.h" +#define DEF_DOMAIN "fidonet.org" +/* + * Our fake expressions checker. Allways return FALSE (?) + */ +bool eventexpr(s_expr *expr) +{ + return FALSE; +} + +static void usage(void) +{ + printf_usage("nodelist lookup utility", + "usage: nlookup [-rmh]
\n" + "\n" + "options:\n" + " -r show nodelist string\n" + " -m show email address\n" + " -h show this help message\n" + "\n" + ); +} + +void print_nodemail(const s_node *node) +{ + char abuf[BF_MAXADDRSTR+1]; + + if( node->sysop && *node->sysop && strcmp(node->sysop, "") ) + { + char username[BNI_MAXSYSOP+1]; + + strnxcpy(username, node->sysop, sizeof(node->sysop)); + string_replchar(username, ' ', '_'); + + printf("%s@%s.fidonet.org\n", username, + ftn_addrstr_inet(abuf, node->addr)); + } + + fflush(stdout); +} + +void print_nodeinfo(const s_node *node) +{ + char abuf[BF_MAXADDRSTR+1]; + + printf("Address : %s\n", ftn_addrstr(abuf, node->addr)); + printf("System : %s\n", node->name); + printf("Phone : %s\n", node->phone); + printf("Sysop : %s\n", node->sysop); + printf("Location : %s\n", node->location); + printf("Speed : %lu\n", node->speed); + printf("Flags : %s\n", node->flags); + + if( node->worktime.num ) + { + char timebuf[80]; + time_t unixtime = time(NULL); + struct tm *now = localtime(&unixtime); + + timevec_string(timebuf, &node->worktime, sizeof(timebuf)); + + printf("Work time : %s (%s)\n", timebuf, + timevec_check(&node->worktime, now) ? "false" : "true"); + } + + if( node->sysop && *node->sysop && strcmp(node->sysop, "") ) + { + char username[BNI_MAXSYSOP+1]; + + strnxcpy(username, node->sysop, sizeof(node->sysop)); + string_replchar(username, ' ', '_'); + + printf("e-mail : %s@%s\n", username, + ftn_addrstr_inet(abuf, node->addr)); + } + + fflush(stdout); +} + +int main(int argc, char *argv[]) +{ + s_node node; + s_faddr addr; + char ch; + bool rawstring = FALSE; + bool emailaddr = FALSE; + + /* Initialise random number generation */ + (void)srand((unsigned)time(0)); + /* Initialise current locale */ + (void)setlocale(LC_ALL, ""); + + while( (ch=getopt(argc, argv, "hrm")) != EOF ) + { + switch( ch ) { + case 'h': + usage(); + exit(BFERR_NOERROR); + case 'r': + rawstring = TRUE; + break; + case 'm': + emailaddr = TRUE; + break; + default: + usage(); + exit(BFERR_FATALERROR); + } + } + + if( optind >= argc || ftn_addrparse(&addr, argv[optind], FALSE) ) + { + usage(); + exit(BFERR_FATALERROR); + } + + if( conf_readconf(conf_getconfname(), 0) ) + exit(BFERR_FATALERROR); + + if( rawstring ) + { + char buf[512]; + + if( nodelist_lookup_string(buf, sizeof(buf), addr) == 0 ) + printf("%s\n", buf); + } + else if( nodelist_lookup(&node, addr) == 0 ) + { + if( emailaddr ) + print_nodemail(&node); + else + print_nodeinfo(&node); + } + + deinit_conf(); + + exit(0); +} diff --git a/source/config.guess b/source/config.guess new file mode 100755 index 0000000..2960d6e --- /dev/null +++ b/source/config.guess @@ -0,0 +1,951 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. +# +# This file 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. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner . +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*|MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + macppc:NetBSD:*:*) + echo powerpc-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${TARGET_BINARY_INTERFACE}x = x ] ; then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/6?? | 9000/7?? | 9000/80[24] | 9000/8?[13679] | 9000/892 ) + sed 's/^ //' << EOF >dummy.c + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (${CC-cc} dummy.c -o dummy 2>/dev/null ) && HP_ARCH=`./dummy` + rm -f dummy.c dummy + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # uname on the ARM produces all sorts of strangeness, and we need to + # filter it out. + case "$UNAME_MACHINE" in + arm* | sa110*) UNAME_MACHINE="arm" ;; + esac + + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c </dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >dummy.c < +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i?86:UnixWare:*:*) + if /bin/uname -X 2>/dev/null >/dev/null ; then + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + fi + echo ${UNAME_MACHINE}-unixware-${UNAME_RELEASE}-${UNAME_VERSION} + exit 0 ;; + pc:*:*:*) + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/source/config.status b/source/config.status new file mode 100755 index 0000000..cc4d561 --- /dev/null +++ b/source/config.status @@ -0,0 +1,1011 @@ +#! /bin/sh +# Generated by configure. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=${CONFIG_SHELL-/bin/sh} +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by bforce $as_me 0.22.8.ugenk2, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +config_files=" Makefile ../debian/Makefile" +config_headers=" include/config.h" + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." +ac_cs_version="\ +bforce config.status 0.22.8.ugenk2 +configured by ./configure, generated by GNU Autoconf 2.59, + with options \"\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=. +INSTALL="/usr/bin/install -c" +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +if $ac_cs_recheck; then + echo "running /bin/sh ./configure " $ac_configure_extra_args " --no-create --no-recursion" >&6 + exec /bin/sh ./configure $ac_configure_extra_args --no-create --no-recursion +fi + +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "../debian/Makefile" ) CONFIG_FILES="$CONFIG_FILES ../debian/Makefile" ;; + "include/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS include/config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t$/@;t t/; /@;t t$/s/[\\&,]/\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t$/,;t t/' >$tmp/subs.sed <<\CEOF +s,@SHELL@,/bin/sh,;t t +s,@PATH_SEPARATOR@,:,;t t +s,@PACKAGE_NAME@,bforce,;t t +s,@PACKAGE_TARNAME@,bforce,;t t +s,@PACKAGE_VERSION@,0.22.8.ugenk2,;t t +s,@PACKAGE_STRING@,bforce 0.22.8.ugenk2,;t t +s,@PACKAGE_BUGREPORT@,ugenk@tut.by,;t t +s,@exec_prefix@,${prefix},;t t +s,@prefix@,/usr/local,;t t +s,@program_transform_name@,s,x,x,,;t t +s,@bindir@,${exec_prefix}/bin,;t t +s,@sbindir@,${exec_prefix}/sbin,;t t +s,@libexecdir@,${exec_prefix}/libexec,;t t +s,@datadir@,${prefix}/share,;t t +s,@sysconfdir@,${prefix}/etc,;t t +s,@sharedstatedir@,${prefix}/com,;t t +s,@localstatedir@,${prefix}/var,;t t +s,@libdir@,${exec_prefix}/lib,;t t +s,@includedir@,${prefix}/include,;t t +s,@oldincludedir@,/usr/include,;t t +s,@infodir@,${prefix}/info,;t t +s,@mandir@,${prefix}/man,;t t +s,@build_alias@,,;t t +s,@host_alias@,,;t t +s,@target_alias@,,;t t +s,@DEFS@,-DHAVE_CONFIG_H,;t t +s,@ECHO_C@,,;t t +s,@ECHO_N@,-n,;t t +s,@ECHO_T@,,;t t +s,@LIBS@,,;t t +s,@build@,i686-pc-linux-gnu,;t t +s,@build_cpu@,i686,;t t +s,@build_vendor@,pc,;t t +s,@build_os@,linux-gnu,;t t +s,@host@,i686-pc-linux-gnu,;t t +s,@host_cpu@,i686,;t t +s,@host_vendor@,pc,;t t +s,@host_os@,linux-gnu,;t t +s,@target@,i686-pc-linux-gnu,;t t +s,@target_cpu@,i686,;t t +s,@target_vendor@,pc,;t t +s,@target_os@,linux-gnu,;t t +s,@OWNER@,uucp,;t t +s,@GROUP@,news,;t t +s,@YACC@,bison -y,;t t +s,@CC@,gcc,;t t +s,@CFLAGS@,-g -O2,;t t +s,@LDFLAGS@,,;t t +s,@CPPFLAGS@,,;t t +s,@ac_ct_CC@,gcc,;t t +s,@EXEEXT@,,;t t +s,@OBJEXT@,o,;t t +s,@INSTALL_PROGRAM@,${INSTALL},;t t +s,@INSTALL_SCRIPT@,${INSTALL},;t t +s,@INSTALL_DATA@,${INSTALL} -m 644,;t t +s,@CPP@,gcc -E,;t t +s,@EGREP@,grep -E,;t t +s,@LIBOBJS@,,;t t +s,@LTLIBOBJS@,,;t t +CEOF + + # 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_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # 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" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi + sed "/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +} + +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done + +# +# CONFIG_HEADER section. +# + +# 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=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + + # Handle all the #define templates only if necessary. + if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then + # If there are no defines, we may have an empty if/fi + : + cat >$tmp/defines.sed <$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in + + cat >$tmp/defines.sed <$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in + + fi # grep + + # Handle all the #undef templates + cat >$tmp/undefs.sed <$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in + + cat >$tmp/undefs.sed <$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done + +{ (exit 0); exit 0; } diff --git a/source/config.sub b/source/config.sub new file mode 100755 index 0000000..00bea6e --- /dev/null +++ b/source/config.sub @@ -0,0 +1,955 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | v850) + basic_machine=$basic_machine-unknown + ;; + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[34567]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + np1) + basic_machine=np1-gould + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | k6 | 6x86) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | nexen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | k6-* | 6x86-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/source/configure b/source/configure new file mode 100755 index 0000000..509fa2b --- /dev/null +++ b/source/configure @@ -0,0 +1,7427 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for bforce 0.22.8.ugenk2. +# +# Report bugs to . +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='bforce' +PACKAGE_TARNAME='bforce' +PACKAGE_VERSION='0.22.8.ugenk2' +PACKAGE_STRING='bforce 0.22.8.ugenk2' +PACKAGE_BUGREPORT='ugenk@tut.by' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#else +# if HAVE_STDINT_H +# include +# endif +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os OWNER GROUP YACC CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CPP EGREP LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +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' + +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 + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # 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_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$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 ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) 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 | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$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 | -n) + 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_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + 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 "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# 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_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + 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 "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CC_set=${CC+set} +ac_env_CC_value=$CC +ac_cv_env_CC_set=${CC+set} +ac_cv_env_CC_value=$CC +ac_env_CFLAGS_set=${CFLAGS+set} +ac_env_CFLAGS_value=$CFLAGS +ac_cv_env_CFLAGS_set=${CFLAGS+set} +ac_cv_env_CFLAGS_value=$CFLAGS +ac_env_LDFLAGS_set=${LDFLAGS+set} +ac_env_LDFLAGS_value=$LDFLAGS +ac_cv_env_LDFLAGS_set=${LDFLAGS+set} +ac_cv_env_LDFLAGS_value=$LDFLAGS +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # 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 <<_ACEOF +\`configure' configures bforce 0.22.8.ugenk2 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of bforce 0.22.8.ugenk2:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-debug enable debugging support (default) + --enable-watch-cd enable DCD line control (default) + --enable-hangup-watch-cd hangup watchs for DCD line (default) + --enable-log-passwd write session password to log (default) + --enable-csy-locks use '.csy' locks while dialing (default) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-owner=USER set possibility to run bforce from a USER (uucp) + --with-group=GROUP set possibility to run bforce from a GROUP (news) + --with-uucp-lockdir specify directory for UUCP style locks + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have + headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to . +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd "$ac_popdir" + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +bforce configure 0.22.8.ugenk2 +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by bforce $as_me 0.22.8.ugenk2, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# 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 + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# 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 "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + + ac_config_headers="$ac_config_headers include/config.h" + +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 + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking target system type" >&5 +echo $ECHO_N "checking target system type... $ECHO_C" >&6 +if test "${ac_cv_target+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_target_alias=$target_alias +test "x$ac_cv_target_alias" = "x" && + ac_cv_target_alias=$ac_cv_host_alias +ac_cv_target=`$ac_config_sub $ac_cv_target_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_target" >&5 +echo "${ECHO_T}$ac_cv_target" >&6 +target=$ac_cv_target +target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + +############### +# Setup version +############### + +if test -f $srcdir/.version ; then + cat >>confdefs.h <<_ACEOF +#define RELEASE_VERSION "`cat $srcdir/.version`" +_ACEOF + +else + cat >>confdefs.h <<\_ACEOF +#define RELEASE_VERSION "?.?" +_ACEOF + +fi + +################### +# Optional features +# +OWNER='uucp' +GROUP='news' + +# Check whether --with-owner or --without-owner was given. +if test "${with_owner+set}" = set; then + withval="$with_owner" + +fi; + + +# Check whether --with-group or --without-group was given. +if test "${with_group+set}" = set; then + withval="$with_group" + +fi; + + + +# Check whether --enable-debug or --disable-debug was given. +if test "${enable_debug+set}" = set; then + enableval="$enable_debug" + if test $enableval = yes; then + cat >>confdefs.h <<\_ACEOF +#define DEBUG 1 +_ACEOF + + fi +else + cat >>confdefs.h <<\_ACEOF +#define DEBUG 1 +_ACEOF + +fi; + +# Check whether --enable-dcd-control or --disable-dcd-control was given. +if test "${enable_dcd_control+set}" = set; then + enableval="$enable_dcd_control" + if test $enableval = yes; then + cat >>confdefs.h <<\_ACEOF +#define MODEM_WATCH_CARRIER 1 +_ACEOF + + fi +else + cat >>confdefs.h <<\_ACEOF +#define MODEM_WATCH_CARRIER 1 +_ACEOF + +fi; + +# Check whether --enable-hangup-watch-cd or --disable-hangup-watch-cd was given. +if test "${enable_hangup_watch_cd+set}" = set; then + enableval="$enable_hangup_watch_cd" + if test $enableval = yes; then + cat >>confdefs.h <<\_ACEOF +#define MODEM_HANGUP_WATCH_CARRIER 1 +_ACEOF + + fi +else + cat >>confdefs.h <<\_ACEOF +#define MODEM_HANGUP_WATCH_CARRIER 1 +_ACEOF + +fi; + +# Check whether --enable-log-passwd or --disable-log-passwd was given. +if test "${enable_log_passwd+set}" = set; then + enableval="$enable_log_passwd" + if test $enableval = yes; then + cat >>confdefs.h <<\_ACEOF +#define BFORCE_LOG_PASSWD 1 +_ACEOF + + fi +else + cat >>confdefs.h <<\_ACEOF +#define BFORCE_LOG_PASSWD 1 +_ACEOF + +fi; + +# Check whether --enable-csy-locks or --disable-csy-locks was given. +if test "${enable_csy_locks+set}" = set; then + enableval="$enable_csy_locks" + if test $enableval = yes; then + cat >>confdefs.h <<\_ACEOF +#define BFORCE_USE_CSY 1 +_ACEOF + + fi +else + cat >>confdefs.h <<\_ACEOF +#define BFORCE_USE_CSY 1 +_ACEOF + +fi; + + +# Check whether --with-uucp-lockdir or --without-uucp-lockdir was given. +if test "${with_uucp_lockdir+set}" = set; then + withval="$with_uucp_lockdir" + cat >>confdefs.h <<_ACEOF +#define BFORCE_LOCK_DIR "$withval" +_ACEOF + +else + echo "$as_me:$LINENO: checking \"UUCP lock files directory\"" >&5 +echo $ECHO_N "checking \"UUCP lock files directory\"... $ECHO_C" >&6 + if test -d /var/lock/serial ; then + lockdir=/var/lock/serial/ + elif test -d /var/spool/lock ; then + lockdir=/var/spool/lock/ + else + lockdir=/var/lock/ + fi + cat >>confdefs.h <<_ACEOF +#define BFORCE_LOCK_DIR "$lockdir" +_ACEOF + + echo "$as_me:$LINENO: result: \"$lockdir\"" >&5 +echo "${ECHO_T}\"$lockdir\"" >&6 + +fi; + +for ac_prog in 'bison -y' byacc +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 "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_YACC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_YACC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + echo "$as_me:$LINENO: result: $YACC" >&5 +echo "${ECHO_T}$YACC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +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 "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +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 $# != 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 + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in 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 "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&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 +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +# 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 +# AmigaOS /C/install, which installs bootblocks on floppy discs +# 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" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /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 + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done + + +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 "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&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}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + + + + + + + + +ac_header_dirent=no +for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do + as_ac_Header=`echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_hdr that defines DIR" >&5 +echo $ECHO_N "checking for $ac_hdr that defines DIR... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include <$ac_hdr> + +int +main () +{ +if ((DIR *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 +_ACEOF + +ac_header_dirent=$ac_hdr; break +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 "$as_me:$LINENO: checking for library containing opendir" >&5 +echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6 +if test "${ac_cv_search_opendir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_opendir=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* 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; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_opendir" = no; then + for ac_lib in dir; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* 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; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 +echo "${ECHO_T}$ac_cv_search_opendir" >&6 +if test "$ac_cv_search_opendir" != no; then + test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS" + +fi + +else + echo "$as_me:$LINENO: checking for library containing opendir" >&5 +echo $ECHO_N "checking for library containing opendir... $ECHO_C" >&6 +if test "${ac_cv_search_opendir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +ac_cv_search_opendir=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* 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; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_search_opendir" = no; then + for ac_lib in x; do + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +#endif +/* 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; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_search_opendir="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_func_search_save_LIBS +fi +echo "$as_me:$LINENO: result: $ac_cv_search_opendir" >&5 +echo "${ECHO_T}$ac_cv_search_opendir" >&6 +if test "$ac_cv_search_opendir" != no; then + test "$ac_cv_search_opendir" = "none required" || LIBS="$ac_cv_search_opendir $LIBS" + +fi + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + 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 <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + 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 <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#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); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5 +echo $ECHO_N "checking for sys/wait.h that is POSIX.1 compatible... $ECHO_C" >&6 +if test "${ac_cv_header_sys_wait_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#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; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_sys_wait_h=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_sys_wait_h=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_wait_h" >&6 +if test $ac_cv_header_sys_wait_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SYS_WAIT_H 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + +for ac_header in fcntl.h sys/file.h sys/ioctl.h sys/time.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## --------------------------- ## +## Report this to ugenk@tut.by ## +## --------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + +for ac_header in termios.h sys/termiox.h sys/vfs.h sys/statfs.h sys/statvfs.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## --------------------------- ## +## Report this to ugenk@tut.by ## +## --------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + +for ac_header in sys/select.h sys/param.h sys/mount.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## --------------------------- ## +## Report this to ugenk@tut.by ## +## --------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6 +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + } +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_const=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6 +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for mode_t" >&5 +echo $ECHO_N "checking for mode_t... $ECHO_C" >&6 +if test "${ac_cv_type_mode_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((mode_t *) 0) + return 0; +if (sizeof (mode_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_mode_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_mode_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_mode_t" >&5 +echo "${ECHO_T}$ac_cv_type_mode_t" >&6 +if test $ac_cv_type_mode_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define mode_t int +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for pid_t" >&5 +echo $ECHO_N "checking for pid_t... $ECHO_C" >&6 +if test "${ac_cv_type_pid_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((pid_t *) 0) + return 0; +if (sizeof (pid_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_pid_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_pid_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5 +echo "${ECHO_T}$ac_cv_type_pid_t" >&6 +if test $ac_cv_type_pid_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define pid_t int +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6 +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((size_t *) 0) + return 0; +if (sizeof (size_t)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_size_t=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6 +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned +_ACEOF + +fi + +echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5 +echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6 +if test "${ac_cv_header_time+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include + +int +main () +{ +if ((struct tm *) 0) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_time=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_time=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5 +echo "${ECHO_T}$ac_cv_header_time" >&6 +if test $ac_cv_header_time = yes; then + +cat >>confdefs.h <<\_ACEOF +#define TIME_WITH_SYS_TIME 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 +echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6 +if test "${ac_cv_struct_tm+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +int +main () +{ +struct tm *tp; tp->tm_sec; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_struct_tm=time.h +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_struct_tm=sys/time.h +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5 +echo "${ECHO_T}$ac_cv_struct_tm" >&6 +if test $ac_cv_struct_tm = sys/time.h; then + +cat >>confdefs.h <<\_ACEOF +#define TM_IN_SYS_TIME 1 +_ACEOF + +fi + + +echo "$as_me:$LINENO: checking whether getpgrp requires zero arguments" >&5 +echo $ECHO_N "checking whether getpgrp requires zero arguments... $ECHO_C" >&6 +if test "${ac_cv_func_getpgrp_void+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Use it with a single arg. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +getpgrp (0); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_getpgrp_void=no +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_getpgrp_void=yes +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +echo "$as_me:$LINENO: result: $ac_cv_func_getpgrp_void" >&5 +echo "${ECHO_T}$ac_cv_func_getpgrp_void" >&6 +if test $ac_cv_func_getpgrp_void = yes; then + +cat >>confdefs.h <<\_ACEOF +#define GETPGRP_VOID 1 +_ACEOF + +fi + +if test $ac_cv_c_compiler_gnu = yes; then + echo "$as_me:$LINENO: checking whether $CC needs -traditional" >&5 +echo $ECHO_N "checking whether $CC needs -traditional... $ECHO_C" >&6 +if test "${ac_cv_prog_gcc_traditional+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_pattern="Autoconf.*'x'" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +Autoconf TIOCGETP +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then + ac_cv_prog_gcc_traditional=yes +else + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +Autoconf TCGETA +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "$ac_pattern" >/dev/null 2>&1; then + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_gcc_traditional" >&5 +echo "${ECHO_T}$ac_cv_prog_gcc_traditional" >&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +echo "$as_me:$LINENO: checking for function prototypes" >&5 +echo $ECHO_N "checking for function prototypes... $ECHO_C" >&6 +if test "$ac_cv_prog_cc_stdc" != no; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +cat >>confdefs.h <<\_ACEOF +#define PROTOTYPES 1 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define __PROTOTYPES 1 +_ACEOF + +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +echo "$as_me:$LINENO: checking whether setvbuf arguments are reversed" >&5 +echo $ECHO_N "checking whether setvbuf arguments are reversed... $ECHO_C" >&6 +if test "${ac_cv_func_setvbuf_reversed+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_func_setvbuf_reversed=no + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +# if PROTOTYPES + int (setvbuf) (FILE *, int, char *, size_t); +# endif +int +main () +{ +char buf; return setvbuf (stdout, _IOLBF, &buf, 1); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +# if PROTOTYPES + int (setvbuf) (FILE *, int, char *, size_t); +# endif +int +main () +{ +char buf; return setvbuf (stdout, &buf, _IOLBF, 1); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + # It compiles and links either way, so it must not be declared + # with a prototype and most likely this is a K&R C compiler. + # Try running it. + if test "$cross_compiling" = yes; then + : # Assume setvbuf is not reversed when cross-compiling. +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +/* This call has the arguments reversed. + A reversed system may check and see that the address of buf + is not _IOLBF, _IONBF, or _IOFBF, and return nonzero. */ + char buf; + if (setvbuf (stdout, _IOLBF, &buf, 1) != 0) + exit (1); + putchar ('\r'); + exit (0); /* Non-reversed systems SEGV here. */ + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_setvbuf_reversed=yes +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +rm -f core *.core +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + ac_cv_func_setvbuf_reversed=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_setvbuf_reversed" >&5 +echo "${ECHO_T}$ac_cv_func_setvbuf_reversed" >&6 +if test $ac_cv_func_setvbuf_reversed = yes; then + +cat >>confdefs.h <<\_ACEOF +#define SETVBUF_REVERSED 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking return type of signal handlers" >&5 +echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6 +if test "${ac_cv_type_signal+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#ifdef signal +# undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int +main () +{ +int i; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_signal=void +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_signal=int +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 +echo "${ECHO_T}$ac_cv_type_signal" >&6 + +cat >>confdefs.h <<_ACEOF +#define RETSIGTYPE $ac_cv_type_signal +_ACEOF + + + +for ac_func in vprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* 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 (); +/* 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 +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +echo "$as_me:$LINENO: checking for _doprnt" >&5 +echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6 +if test "${ac_cv_func__doprnt+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define _doprnt to an innocuous variant, in case declares _doprnt. + For example, HP-UX 11i declares gettimeofday. */ +#define _doprnt innocuous__doprnt + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _doprnt (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef _doprnt + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt (); +/* 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__doprnt) || defined (__stub____doprnt) +choke me +#else +char (*f) () = _doprnt; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != _doprnt; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func__doprnt=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func__doprnt=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5 +echo "${ECHO_T}$ac_cv_func__doprnt" >&6 +if test $ac_cv_func__doprnt = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_DOPRNT 1 +_ACEOF + +fi + +fi +done + + + + + + + + +for ac_func in mkdir mktime select socket strspn strcasecmp +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* 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 (); +/* 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 +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + + +for ac_func in rename statfs statvfs setproctitle +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* 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 (); +/* 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 +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + ac_config_files="$ac_config_files Makefile" +cat >confcache <<\_ACEOF +# 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, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# 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 \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by bforce $as_me 0.22.8.ugenk2, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +bforce config.status 0.22.8.ugenk2 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "include/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS include/config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@target@,$target,;t t +s,@target_cpu@,$target_cpu,;t t +s,@target_vendor@,$target_vendor,;t t +s,@target_os@,$target_os,;t t +s,@OWNER@,$OWNER,;t t +s,@GROUP@,$GROUP,;t t +s,@YACC@,$YACC,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # 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_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # 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" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# 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=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# 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.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# 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.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + + ac_config_files="$ac_config_files ../debian/Makefile" +cat >confcache <<\_ACEOF +# 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, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# 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 \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by bforce $as_me 0.22.8.ugenk2, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +bforce config.status 0.22.8.ugenk2 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +INSTALL="$INSTALL" +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + + + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "../debian/Makefile" ) CONFIG_FILES="$CONFIG_FILES ../debian/Makefile" ;; + "include/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS include/config.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@target@,$target,;t t +s,@target_cpu@,$target_cpu,;t t +s,@target_vendor@,$target_vendor,;t t +s,@target_os@,$target_os,;t t +s,@OWNER@,$OWNER,;t t +s,@GROUP@,$GROUP,;t t +s,@YACC@,$YACC,;t t +s,@CC@,$CC,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@LDFLAGS@,$LDFLAGS,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t +s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t +s,@INSTALL_DATA@,$INSTALL_DATA,;t t +s,@CPP@,$CPP,;t t +s,@EGREP@,$EGREP,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # 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_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # 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" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_builddir$INSTALL ;; + esac + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +s,@INSTALL@,$ac_INSTALL,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# 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=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# 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.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# 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.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/source/configure.in b/source/configure.in new file mode 100644 index 0000000..2759b73 --- /dev/null +++ b/source/configure.in @@ -0,0 +1,109 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl $Id$ +dnl +#AC_INIT(bforce/bforce.c) +AC_INIT([bforce],[0.22.8.ugenk2],[ugenk@tut.by]) +AC_CONFIG_HEADER(include/config.h) +AC_CANONICAL_SYSTEM +dnl # Minimum Autoconf version required. +AC_PREREQ(2.50) + +############### +# Setup version +############### + +if [ test -f $srcdir/.version ]; then + AC_DEFINE_UNQUOTED(RELEASE_VERSION, "`cat $srcdir/.version`") +else + AC_DEFINE(RELEASE_VERSION, "?.?") +fi + +################### +# Optional features +# +OWNER='uucp' +GROUP='news' +AC_ARG_WITH(owner, dnl + --with-owner=USER set possibility to run bforce from a USER (uucp), + ) +AC_SUBST(OWNER) +AC_ARG_WITH(group, dnl + --with-group=GROUP set possibility to run bforce from a GROUP (news), + ) +AC_SUBST(GROUP) + + +AC_ARG_ENABLE(debug, [ --enable-debug enable debugging support (default)], + [if test $enableval = yes; then + AC_DEFINE(DEBUG) + fi], [AC_DEFINE(DEBUG)]) + +AC_ARG_ENABLE(dcd-control, [ --enable-watch-cd enable DCD line control (default)], + [if test $enableval = yes; then + AC_DEFINE(MODEM_WATCH_CARRIER) + fi], [AC_DEFINE(MODEM_WATCH_CARRIER)]) + +AC_ARG_ENABLE(hangup-watch-cd, [ --enable-hangup-watch-cd hangup watchs for DCD line (default)], + [if test $enableval = yes; then + AC_DEFINE(MODEM_HANGUP_WATCH_CARRIER) + fi], [AC_DEFINE(MODEM_HANGUP_WATCH_CARRIER)]) + +AC_ARG_ENABLE(log-passwd, [ --enable-log-passwd write session password to log (default)], + [if test $enableval = yes; then + AC_DEFINE(BFORCE_LOG_PASSWD) + fi], [AC_DEFINE(BFORCE_LOG_PASSWD)]) + +AC_ARG_ENABLE(csy-locks, [ --enable-csy-locks use '.csy' locks while dialing (default)], + [if test $enableval = yes; then + AC_DEFINE(BFORCE_USE_CSY) + fi], [AC_DEFINE(BFORCE_USE_CSY)]) + +AC_ARG_WITH(uucp-lockdir, [ --with-uucp-lockdir specify directory for UUCP style locks], + [AC_DEFINE_UNQUOTED(BFORCE_LOCK_DIR, "$withval")], + [AC_MSG_CHECKING("UUCP lock files directory") + if test -d /var/lock/serial ; then + lockdir=/var/lock/serial/ + elif test -d /var/spool/lock ; then + lockdir=/var/spool/lock/ + else + lockdir=/var/lock/ + fi + AC_DEFINE_UNQUOTED(BFORCE_LOCK_DIR, "$lockdir") + AC_MSG_RESULT("$lockdir") + ]) + +dnl Checks for programs. +AC_PROG_YACC +AC_PROG_CC +AC_PROG_INSTALL + +dnl Checks for libraries. + +dnl Checks for header files. +AC_HEADER_DIRENT +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h sys/file.h sys/ioctl.h sys/time.h unistd.h) +AC_CHECK_HEADERS(termios.h sys/termiox.h sys/vfs.h sys/statfs.h sys/statvfs.h) +AC_CHECK_HEADERS(sys/select.h sys/param.h sys/mount.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_MODE_T +AC_TYPE_PID_T +AC_TYPE_SIZE_T +AC_HEADER_TIME +AC_STRUCT_TM + +dnl Checks for library functions. +AC_FUNC_GETPGRP +AC_PROG_GCC_TRADITIONAL +AC_FUNC_SETVBUF_REVERSED +AC_TYPE_SIGNAL +AC_FUNC_VPRINTF +AC_CHECK_FUNCS(mkdir mktime select socket strspn strcasecmp) +AC_CHECK_FUNCS(rename statfs statvfs setproctitle) + +AC_OUTPUT(Makefile) +AC_OUTPUT(../debian/Makefile) diff --git a/source/include/acconfig.h b/source/include/acconfig.h new file mode 100644 index 0000000..a2af565 --- /dev/null +++ b/source/include/acconfig.h @@ -0,0 +1,22 @@ + +/* Do you want debug code to be compiled? */ +#undef DEBUG + +/* Do you want use DCD line control? */ +#undef MODEM_WATCH_CARRIER + +/* Do you want hangup to watch for modem DCD line? */ +#undef MODEM_HANGUP_WATCH_CARRIER + +/* Version string */ +#undef RELEASE_VERSION + +/* Disable passwords logging? */ +#undef BFORCE_LOG_PASSWD + +/* Path to the UUCP lock files directory */ +#undef BFORCE_LOCK_DIR + +/* Do you want use .csy locks? */ +#undef BFORCE_USE_CSY + diff --git a/source/include/bforce.h b/source/include/bforce.h new file mode 100644 index 0000000..fb9be7e --- /dev/null +++ b/source/include/bforce.h @@ -0,0 +1,191 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _BFORCE_H_ +#define _BFORCE_H_ + +#ifndef DAEMON_LOGFILE +#define DAEMON_LOGFILE "/var/log/bforce/bf-daemon" +#endif + +#ifndef BFORCE_LOGFILE +#define BFORCE_LOGFILE "/var/log/bforce/bf-log" +#endif + +#ifndef BFORCE_DEBFILE +#define BFORCE_DEBFILE "/var/log/bforce/bf-debug" +#endif + +#ifndef BFORCE_CFGFILE +#define BFORCE_CFGFILE "/etc/bforce/bforce.conf" +#endif + +/* + * BinkleyForce limits + */ +#define BF_MAXCFGLINE 512 +#define BF_MAXREQLINE 256 +#define BF_MAXPATH 256 +#define BF_MAXDOMAIN 40 +#define BF_MAXADDRSTR 80 + +/* + * Maximum length of file name (without path) + */ +#define BFORCE_MAX_NAME 128 + +/* + * Maximum path length, including file name length + */ +#define BFORCE_MAX_PATH 256 + +/* + * Maximum length of address string + */ +#define BFORCE_MAX_ADDRSTR 80 + +/* + * Lock files type: + * 1 - Ascii lock files + * 2 - Binary lock files + * 3 - SVR4 lock files (not implemented) + */ +#define BFORCE_LOCK_TYPE 1 + +/* + * Maximum length of phone number string + */ +#define BFORCE_MAX_PHONE 80 + +/* + * Maximum length of modem command string. Most modems + * cannot handle strings longer 40 characters. + */ +#define MODEM_MAX_COMMAND 120 + +/* + * Maximum length of modem response string + */ +#define MODEM_MAX_RESP 120 + +/* + * Maximum number of characters that modem can response + * on something command. Responses larger this will be + * considered invalid, and mailer will return "modem not + * response" without further waiting for "OK" or "ERROR" + */ +#define MODEM_MAX_RESP_SIZE 8128 + +/* + * BinkleyForce return codes + */ +#define BFERR_NOERROR 0 +#define BFERR_FATALERROR 1 +#define BFERR_PHONE_UNKNOWN 2 +#define BFERR_PORTBUSY 3 +#define BFERR_SYSTEM_LOCKED 4 +#define BFERR_TRY_LATER 5 +#define BFERR_NOMODEM 6 +#define BFERR_NOTWORKING 7 +#define BFERR_CANT_CONNECT10 10 +#define BFERR_CANT_CONNECT11 11 +#define BFERR_CANT_CONNECT12 12 +#define BFERR_CANT_CONNECT13 13 +#define BFERR_CANT_CONNECT14 14 +#define BFERR_CANT_CONNECT15 15 +#define BFERR_CANT_CONNECT16 16 +#define BFERR_CANT_CONNECT17 17 +#define BFERR_CANT_CONNECT18 18 +#define BFERR_CANT_CONNECT19 19 +#define BFERR_CONNECT_TOOLOW 20 +#define BFERR_HANDSHAKE_ERROR 21 +#define BFERR_XMITERROR 22 +#define BFERR_CPSTOOLOW 23 +#define BFERR_STOPTIME 24 + +#define BFERR_MAXERRNO 24 /* Maximal error number */ + +#define BFERR_NAME(rc) ((rc >= 0) && (rc <= BFERR_MAXERRNO) ? BFERR[rc] : "Out of range") + +/* + * Some most popular defines + */ +#define gotoexit(a) { rc = a; goto exit; } + +#ifdef __GNUC__ +#define ASSERT_MSG() log("assertion failed: file: %s, line: %d, function: %s", \ + __FILE__, __LINE__, __FUNCTION__); +#else +#define ASSERT_MSG() log("assertion failed: file: %s, line: %d", \ + __FILE__, __LINE__); +#endif + +#define ASSERT(expr) \ + if( !(expr) ) \ + { \ + ASSERT_MSG(); \ + abort(); \ + } + +#define ISHEX(s) (strspn(s, "0123456790abcdefABCDEF") == strlen(s)) +#define ISDEC(s) (strspn(s, "0123456789" ) == strlen(s)) +#define ISOCT(s) (strspn(s, "01234567" ) == strlen(s)) + +/* + * Some usable defines + */ +#define FALSE 0 +#define TRUE 1 +#define UNDEF -1 + +/* + * Definition of new pretty types + */ +typedef char bool; +typedef unsigned long UINT32; +typedef unsigned short UINT16; +typedef unsigned char UINT8; +typedef signed long SINT32; +typedef signed short SINT16; +typedef signed char SINT8; + +#include "confread.h" + +/* + * Command line options + */ +typedef struct { + bool daemon; /* Run as daemon? */ + bool quit; /* Quit from daemon */ + bool dontcall; /* -m key */ + int inetd; /* Called from inetd? */ + int force; /* Force call? */ + int hiddline; /* Hidden line number (0,1..) */ + char *confname; /* Use this config instead def. */ + char *incname; /* Include this config */ + char *phone; /* Forced phone number */ + char *iaddr; /* Forced IP address */ + char *connect; /* Connect string */ + char *device; /* Forced device name */ + int stype; /* Handshake type in slave mode */ + s_falist *addrlist; +} s_bforce_opts; + +/* + * Global variables + */ +extern const char *BFERR[]; + +int daemon_run(const char *confname, const char *incname, bool quit); + +#endif diff --git a/source/include/config.h b/source/include/config.h new file mode 100644 index 0000000..33a2ac3 --- /dev/null +++ b/source/include/config.h @@ -0,0 +1,145 @@ +/* include/config.h. Generated by configure. */ +/* include/config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define if the `getpgrp' function takes no argument. */ +#define GETPGRP_VOID 1 + +/* Define if you don't have vprintf but do have _doprnt. */ +/* #undef HAVE_DOPRNT */ + +/* Define if you have that is POSIX.1 compatible. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define if you have the vprintf function. */ +#define HAVE_VPRINTF 1 + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `int' if doesn't define. */ +/* #undef pid_t */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define if the setvbuf function takes the buffering type as its second + argument and the buffer pointer as the third, as on System V + before release 3. */ +/* #undef SETVBUF_REVERSED */ + +/* Define to `unsigned' if doesn't define. */ +/* #undef size_t */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define if your declares struct tm. */ +/* #undef TM_IN_SYS_TIME */ + +/* Do you want debug code to be compiled? */ +#define DEBUG 1 + +/* Do you want use DCD line control? */ +#define MODEM_WATCH_CARRIER 1 + +/* Do you want hangup to watch for modem DCD line? */ +#define MODEM_HANGUP_WATCH_CARRIER 1 + +/* Version string */ +#define RELEASE_VERSION "0.22.8.ugenk4" + +/* Disable passwords logging? */ +#define BFORCE_LOG_PASSWD 1 + +/* Path to the UUCP lock files directory */ +#define BFORCE_LOCK_DIR "/var/lock/" + +/* Do you want use .csy locks? */ +#define BFORCE_USE_CSY 1 + +/* Define if you have the mkdir function. */ +#define HAVE_MKDIR 1 + +/* Define if you have the mktime function. */ +#define HAVE_MKTIME 1 + +/* Define if you have the rename function. */ +#define HAVE_RENAME 1 + +/* Define if you have the select function. */ +#define HAVE_SELECT 1 + +/* Define if you have the setproctitle function. */ +/* #undef HAVE_SETPROCTITLE */ + +/* Define if you have the socket function. */ +#define HAVE_SOCKET 1 + +/* Define if you have the statfs function. */ +#define HAVE_STATFS 1 + +/* Define if you have the statvfs function. */ +#define HAVE_STATVFS 1 + +/* Define if you have the strcasecmp function. */ +#define HAVE_STRCASECMP 1 + +/* Define if you have the strspn function. */ +#define HAVE_STRSPN 1 + +/* Define if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_FILE_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STATFS_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_STATVFS_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_TERMIOX_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_VFS_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 diff --git a/source/include/config.h.in b/source/include/config.h.in new file mode 100644 index 0000000..4651350 --- /dev/null +++ b/source/include/config.h.in @@ -0,0 +1,144 @@ +/* include/config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define if the `getpgrp' function takes no argument. */ +#undef GETPGRP_VOID + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define to `int' if doesn't define. */ +#undef mode_t + +/* Define to `int' if doesn't define. */ +#undef pid_t + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define if the setvbuf function takes the buffering type as its second + argument and the buffer pointer as the third, as on System V + before release 3. */ +#undef SETVBUF_REVERSED + +/* Define to `unsigned' if 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 and . */ +#undef TIME_WITH_SYS_TIME + +/* Define if your declares struct tm. */ +#undef TM_IN_SYS_TIME + +/* Do you want debug code to be compiled? */ +#undef DEBUG + +/* Do you want use DCD line control? */ +#undef MODEM_WATCH_CARRIER + +/* Do you want hangup to watch for modem DCD line? */ +#undef MODEM_HANGUP_WATCH_CARRIER + +/* Version string */ +#undef RELEASE_VERSION + +/* Disable passwords logging? */ +#undef BFORCE_LOG_PASSWD + +/* Path to the UUCP lock files directory */ +#undef BFORCE_LOCK_DIR + +/* Do you want use .csy locks? */ +#undef BFORCE_USE_CSY + +/* Define if you have the mkdir function. */ +#undef HAVE_MKDIR + +/* Define if you have the mktime function. */ +#undef HAVE_MKTIME + +/* Define if you have the rename function. */ +#undef HAVE_RENAME + +/* Define if you have the select function. */ +#undef HAVE_SELECT + +/* Define if you have the setproctitle function. */ +#undef HAVE_SETPROCTITLE + +/* Define if you have the socket function. */ +#undef HAVE_SOCKET + +/* Define if you have the statfs function. */ +#undef HAVE_STATFS + +/* Define if you have the statvfs function. */ +#undef HAVE_STATVFS + +/* Define if you have the strcasecmp function. */ +#undef HAVE_STRCASECMP + +/* Define if you have the strspn function. */ +#undef HAVE_STRSPN + +/* Define if you have the header file. */ +#undef HAVE_DIRENT_H + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_MOUNT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_STATFS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_STATVFS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TERMIOX_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_VFS_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H diff --git a/source/include/confread.h b/source/include/confread.h new file mode 100644 index 0000000..d723e0c --- /dev/null +++ b/source/include/confread.h @@ -0,0 +1,363 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _CONFREAD_H_ +#define _CONFREAD_H_ + +#include "util.h" + +/* Constatnts for gotfile switches */ +#define GOTFILE_SW_SRIF 0x01 +#define GOTFILE_SW_IMMED 0x01 +#define GOTFILE_SW_ONLINE 0x01 + +#define MAXINCLUDELEVEL 10 + +#define PROC_RC_OK 0 /* Successfully processed string */ +#define PROC_RC_WARN 1 /* Successfully, but not all so good */ +#define PROC_RC_IGNORE 2 /* Line was ignored, but we can continue */ +#define PROC_RC_ABORT 3 /* Incorrect line and we can not continue */ + +/* + * Options (from/for "options" keyword) + */ +#define OPTIONS_NO_ZMODEM 0x00000001L +#define OPTIONS_NO_ZEDZAP 0x00000002L +#define OPTIONS_NO_DIRZAP 0x00000004L +#define OPTIONS_NO_JANUS 0x00000008L +#define OPTIONS_NO_HYDRA 0x00000010L +#define OPTIONS_NO_BINKP 0x00000020L +#define OPTIONS_NO_TCP 0x00000040L +#define OPTIONS_NO_CHAT 0x00000080L +#define OPTIONS_NO_FTS1 0x00000100L +#define OPTIONS_NO_YOOHOO 0x00000200L +#define OPTIONS_NO_EMSI 0x00000400L +#define OPTIONS_NO_EMSI_II 0x00000800L +#define OPTIONS_NO_FREQS 0x00001000L +#define OPTIONS_MAILONLY 0x00002000L +#define OPTIONS_HOLDXT 0x00004000L +#define OPTIONS_HOLDREQ 0x00008000L +#define OPTIONS_HOLDALL 0x00010000L +#define OPTIONS_HOLDHOLD 0x00020000L +#define OPTIONS_NO_PICKUP 0x00040000L +#define OPTIONS_NO_RH1 0x00080000L +#define OPTIONS_NO_INTRO 0x00100000L + +#define RESPTYPE_CONNECT 0x0000L +#define RESPTYPE_BUSY 0x0001L +#define RESPTYPE_NOCARRIER 0x0002L +#define RESPTYPE_NODIALTONE 0x0004L +#define RESPTYPE_NOANSWER 0x0008L +#define RESPTYPE_ERROR 0x0010L + +#define TRIES_ACTION_UNDIALABLE 0x01 +#define TRIES_ACTION_HOLDSYSTEM 0x02 +#define TRIES_ACTION_HOLDALL 0x04 + +/* + * Add new entry to the end of list + */ +#define LIST_NEWENT(newp,list,type) \ + for( newp = list; *newp; newp = &((*newp)->next) ); \ + *newp = (type*)xmalloc(sizeof(type)); \ + memset(*newp, '\0', sizeof(type)); + +typedef struct expr { + bool error; /* Incorrect expression. Don't try twice! */ + char *expr; /* Pointer to the expression string */ +} s_expr; + +/* + * Storage structures for base config components + */ +typedef struct string { + char *str; +} s_string; + +typedef struct number { + long num; +} s_number; + +typedef struct boolean { + bool istrue; +} s_boolean; + +typedef struct falist { + s_faddr addr; + char *what; + struct falist *next; +} s_falist; + +typedef struct domain { + char *domain; + char *path; + int zone; +} s_domain; + +typedef struct translate { + char *find; + char *repl; +} s_translate; + +typedef struct connlist { + long speed; + long value; +} s_connlist; + +typedef struct dialresp { + char *mstr; /* Modem string/substring */ + int type; /* Response meaning (for mailer) */ + int retv; /* Force this return code */ +} s_dialresp; + +typedef struct filemode { + mode_t mode; +} s_filemode; + +typedef struct modemport { + long speed; + char *name; +} s_modemport; + +typedef struct tries { + int tries; + int action; + int arg; +} s_tries; + +typedef struct override { + s_faddr addr; /* Overrides for this address */ + char *sIpaddr; + char *sPhone; + char *sFlags; + s_timevec worktime; + s_timevec freqtime; + struct override *hidden; /* Hidden lines list */ +} s_override; + +typedef struct options { + unsigned long value; + unsigned long mask; /* bit[k] == 1 if bit[k] defined in value */ +} s_options; + +typedef struct filebox { + s_faddr addr; + char *path; + int flavor; + struct falist *next; +} s_filebox; + +typedef enum { + cf_address, + cf_amiga_outbound_directory, + cf_binkp_timeout, + cf_daemon_circle, + cf_daemon_circle_crash, + cf_daemon_circle_direct, + cf_daemon_circle_immed, + cf_daemon_circle_modem, + cf_daemon_circle_normal, + cf_daemon_circle_rescan, + cf_daemon_maxclients_modem, + cf_daemon_maxclients_tcpip, + cf_daemon_pid_file, + cf_delay_files_recv, + cf_delay_files_send, + cf_disable_aka_matching, + cf_domain, + cf_emsi_FR_time, + cf_emsi_OH_time, + cf_emsi_slave_sends_nak, + cf_filebox, + cf_filebox_directory, + cf_flags, + cf_flo_translate, + cf_freq_alias_list, + cf_freq_dir_list, + cf_freq_ignore_masks, + cf_freq_limit_number, + cf_freq_limit_size, + cf_freq_limit_time, + cf_freq_min_speed, + cf_freq_srif_command, + cf_hide_our_aka, + cf_history_file, + cf_hydra_options, + cf_hydra_mincps_recv, + cf_hydra_mincps_send, + cf_hydra_tx_window, + cf_hydra_rx_window, + cf_inbound_directory, + cf_location, + cf_log_file, + cf_log_file_daemon, + cf_max_speed, + cf_maxtries, + cf_maxtries_nodial, + cf_maxtries_noansw, + cf_maxtries_noconn, + cf_maxtries_hshake, + cf_maxtries_sessions, + cf_min_cps_recv, + cf_min_cps_send, + cf_min_cps_time, + cf_min_free_space, + cf_min_speed_in, + cf_min_speed_out, + cf_mode_netmail, + cf_mode_arcmail, + cf_mode_request, + cf_mode_ticfile, + cf_mode_default, + cf_modem_can_send_break, + cf_modem_dial_prefix, + cf_modem_dial_suffix, + cf_modem_dial_response, + cf_modem_hangup_command, + cf_modem_port, + cf_modem_reset_command, + cf_modem_stat_command, + cf_nodelist, + cf_nodelist_directory, + cf_nodial_flag, + cf_override, + cf_options, + cf_outbound_directory, + cf_password, + cf_phone, + cf_phone_translate, + cf_recode_file_in, + cf_recode_file_out, + cf_recode_intro_in, + cf_recv_buffer_size, + cf_rescan_delay, + cf_run_after_handshake, + cf_run_after_session, + cf_session_limit_in, + cf_session_limit_out, + cf_skip_files_recv, + cf_status_directory, + cf_system_name, + cf_sysop_name, + cf_uucp_lock_directory, + cf_wait_carrier_in, + cf_wait_carrier_out, + cf_zmodem_mincps_recv, + cf_zmodem_mincps_send, + cf_zmodem_send_dummy_pkt, + cf_zmodem_skip_by_pos, + cf_zmodem_start_block_size, + cf_zmodem_tx_window, + cf_nomail_flag, + cf_bind_ip, +/* #ifdef USE_SYSLOG */ + cf_syslog_facility, +/* #endif */ +#ifdef DEBUG + cf_debug_file, + cf_debug_level, +#endif + BFORCE_NUMBER_OF_KEYWORDS +} bforce_config_keyword; + +typedef struct cval_entry { + s_expr expr; + union { + s_falist falist; + s_domain domain; + s_override override; + s_options options; + s_translate translate; + s_connlist connlist; + s_number number; + s_boolean boolean; + s_string string; + s_modemport modemport; + s_dialresp dialresp; + s_tries tries; + s_filemode filemode; + s_filebox filebox; + } d; + struct cval_entry *next; +} s_cval_entry; + +typedef struct conf_entry { + char *name; + enum { + CT_ADDRESS, + CT_BOOLEAN, + CT_CONNLIST, + CT_DIALRESP, + CT_DOMAIN, + CT_FILEMODE, + CT_MODEMPORT, + CT_NODELIST, + CT_NUMBER, + CT_OPTIONS, + CT_OVERRIDE, + CT_PATH, + CT_PASSWORD, + CT_STRING, + CT_TRANSLATE, + CT_TRIES, + CT_DEBLEVEL, + CT_FILEBOX + } type; + s_cval_entry *data; + bforce_config_keyword real_key; +} s_conf_entry; + +extern s_conf_entry bforce_config[]; + +/* conf_proc.c */ +int proc_configline(const char *k, const char *e, const char *v); + +/* conf_deinit.c */ +void deinit_conf(void); +void deinit_cval_entry(s_cval_entry *dest, bforce_config_keyword type); +void deinit_dialresp(s_dialresp *dest); +void deinit_domain(s_domain *dest); +void deinit_expr(s_expr *dest); +void deinit_falist(s_falist *dest); +void deinit_modemport(s_modemport *dest); +void deinit_override(s_override *dest); +void deinit_string(s_string *dest); +void deinit_translate(s_translate *dest); + +/* conf_read.c */ +const char *conf_getconfname(void); +int conf_postreadcheck(void); +int conf_readpasswdlist(s_falist **pwdlist, char *fname); +int conf_readconf(const char *confname, int inclevel); +#ifdef DEBUG +void log_overridelist(s_override *subst); +void log_options(s_options *opt); +#endif + +/* conf_get.c */ +s_cval_entry *conf_first(bforce_config_keyword keyword); +s_cval_entry *conf_next(s_cval_entry *ptrl); +bool conf_boolean(bforce_config_keyword keyword); +mode_t conf_filemode(bforce_config_keyword keyword); +long conf_options(bforce_config_keyword keyword); +long conf_connlist(bforce_config_keyword keyword, long speed); +char *conf_string(bforce_config_keyword keyword); +long conf_number(bforce_config_keyword keyword); +s_override *conf_override(bforce_config_keyword keyword, s_faddr addr); +s_tries *conf_tries(bforce_config_keyword keyword); + +/* expression.y */ +bool eventexpr(s_expr *expr); + +#endif /* _CONFREAD_H_ */ + diff --git a/source/include/daemon.h b/source/include/daemon.h new file mode 100644 index 0000000..a3fbb58 --- /dev/null +++ b/source/include/daemon.h @@ -0,0 +1,93 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _DAEMON_H_ +#define _DAEMON_H_ + +#include "outbound.h" + +/* + * Branch information + */ +typedef struct { + s_faddr addr; + bool tcpip; + char *portname; + bool wait; /* It is like a zombie! */ + pid_t pid; /* Branch PID, returned by fork() call */ + time_t start; + time_t stop; /* We should stop (kill) branch at this time */ + int rc; /* Process return code (one of BFERR values) */ +} s_daemon_branch; + +/* + * Daemon queue sates + */ +typedef enum { + DQ_CallSystem, + DQ_GetNextSystem, + DQ_Idle +} DQ_State; + +/* + * Daemon states + */ +typedef enum { + DM_Start, + DM_Restart, + DM_ProcessQueues, + DM_Usr1, + DM_Usr2, + DM_Shutdown +} DM_State; + +/* + * Daemon queue + */ +typedef struct { + s_sysqueue *q; /* Pointer to the systems queue (shared) */ + int current; + int circle; + bool tcpip; /* Queue for TCP/IP systems? */ + DQ_State state; +} s_daemon_queue; + +extern int max_tcpip; +extern int max_modem; +extern int tcpip_clients; +extern int modem_clients; + +/* daemon.c */ +int daemon_run(const char *confname, const char *incname, bool quit); + +/* daemon_branch.c */ +bool daemon_branch_exist(s_faddr addr); +void daemon_branch_check_stop_timers(void); +int daemon_branch_exit(pid_t pid, int rc); +int daemon_branch_get_first_waiting(void); +s_daemon_branch *daemon_branch_get_pointer(int pos); +void daemon_branch_add(s_faddr addr, pid_t pid, bool tcpip, const char *pname); +void daemon_branch_remove(int pos); +int daemon_branch_number(void); +void daemon_branch_deinit(void); + +/* daemon_call.c */ +int daemon_call(s_sysentry *syst); + +/* daemon_lines.c */ +int daemon_line_add(const char *name, int type); +void daemon_line_hold(const char *name, int holdtime); +bool daemon_line_isready(const char *name); +void daemon_lines_deinit(void); + +#endif /* _DAEMON_H_ */ diff --git a/source/include/freq.h b/source/include/freq.h new file mode 100644 index 0000000..c69851a --- /dev/null +++ b/source/include/freq.h @@ -0,0 +1,70 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _FREQ_H_ +#define _FREQ_H_ + +#include "session.h" +#include "outbound.h" + +/* + * List of our available for FREQing resources + */ +typedef struct frlist { + struct frlist *next; + char *magic; + char *path; + char *passwd; + char *expr; /* process only if expression is true */ +} s_frlist; + +/* + * List of requested files (from requester) + */ +typedef struct reqlist { + struct reqlist *next; + char *fmask; + char *passwd; + time_t newer; + time_t older; + int skip; +} s_reqlist; + +/* + * Keep all FREQ processor-important information here + */ +typedef struct freq { + char *srifproc; /* Name of external (SRIF) FREQ processor */ + s_frlist *frlist; /* File areas list for int. FREQ processor */ + s_reqlist *reqlist; /* List of requested file masks, etc.. */ + s_filelist **filelist; /* Put here files we found and want to send */ + s_filelist **flast; /* Pointer to the last entry in filelist */ + int fnumber; /* Total number of files, we found */ + int fileslimit; /* Maxmum number of files to send as answer */ + size_t fsize; /* Total size of files, we found */ + size_t sizelimit; /* Maxmum size of files to send as answer */ +} s_freq; + +/* req_bark.c */ + +/* req_proc.c */ +void req_proc(char *reqname, s_filelist **filelist); + +/* req_srif.c */ +int req_createsrif(char *sname, char *req, char *rsp); +void req_addfilelist(char *listname, s_freq *freq); + +/* req_wazo.c */ +int req_readwazooreq(char *reqname, s_reqlist **reqlist); + +#endif diff --git a/source/include/includes.h b/source/include/includes.h new file mode 100644 index 0000000..d90b400 --- /dev/null +++ b/source/include/includes.h @@ -0,0 +1,143 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _INCLUDES_H_ +#define _INCLUDES_H_ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Has ANSI C headers? + */ +#ifdef STDC_HEADERS +# include +# include +#else +# include +#endif + +#ifdef HAVE_SYS_WAIT_H +# include +#endif +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_NDIR_H +# include +# endif +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +#endif + +#ifdef HAVE_SYS_FILE_H +#include +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_MOUNT_H +#include +#endif + +#ifdef HAVE_SYS_STATFS_H +#include +#endif + +#ifdef HAVE_SYS_STATVFS_H +#include +#endif + +#ifdef HAVE_SYS_VFS_H +#include +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#elif HAVE_SYS_TIME +# include +#else +# include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_TERMIOS_H +#include +#endif + +#ifdef HAVE_SYS_TERMIOX_H +#include +#endif + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +/* + * Include OS dependent information + */ +#include "os.h" + +/* + * Include version information + */ +#include "version.h" + +/* + * Include main defines, constants + */ +#include "bforce.h" + +#endif diff --git a/source/include/io.h b/source/include/io.h new file mode 100644 index 0000000..363aec3 --- /dev/null +++ b/source/include/io.h @@ -0,0 +1,230 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _IO_H_ +#define _IO_H_ + +typedef enum { + TCPMODE_RAW, + TCPMODE_TELNET, + TCPMODE_BINKP +} e_tcpmode; + +extern int tty_online; +extern int tty_hangup; +extern int tty_abort; +extern int tty_modem; +extern int tty_status; + +#define XON ('Q' & 037) +#define XOFF ('S' & 037) +#define CPMEOF ('Z' & 037) +#define NUL 0x00 +#define SOH 0x01 +#define STX 0x02 +#define ETX 0x03 +#define EOT 0x04 +#define ENQ 0x05 +#define ACK 0x06 +#define BEL 0x07 +#define BS 0x08 +#define HT 0x09 +#define LF 0x0a +#define VT 0x0b +#define FF 0x0c +#define CR 0x0d +#define SO 0x0e +#define SI 0x0f +#define DLE 0x10 +#define DC1 0x11 +#define DC2 0x12 +#define DC3 0x13 +#define DC4 0x14 +#define NAK 0x15 +#define SYN 0x16 +#define ETB 0x17 +#define CAN 0x18 +#define EM 0x19 +#define SUB 0x1a +#define ESC 0x1b +#define FS 0x1c +#define GS 0x1d +#define RS 0x1e +#define US 0x1f +#define TSYNC 0xae +#define YOOHOO 0xf1 + + /* DON'T CHANGE THIS VALUES! */ + /* SOME DON'T USE MACROS */ +#define TTY_SUCCESS 0 +#define TTY_TIMEOUT -1 +#define TTY_HANGUP -2 +#define TTY_ERROR -3 + +#define XSELECT(a,b,c) tty_xselect(a, b, c) +#define WRITE(a,b) tty_write(a, b) +#define READ(a,b) tty_read(a, b) +#define WRITE_TIMEOUT(a,b) tty_write_timeout(a, b, 30) +#define READ_TIMEOUT(a,b,c) tty_read_timeout(a, b, c) +#define GETCHAR(a) tty_getc(a) +#define CHARWAIT(a) tty_charwait(a) +#define PUTCHAR(a) tty_putc(a, 30) +#define BUFCHAR(a) tty_bufc(a, 30) +#define PUTSTR(a) tty_puts(a, 30) +#define CLEARIN() tty_clearin() +#define CLEAROUT() tty_clearout() +#define FLUSHOUT() tty_flushout() +#define FLUSHBUF() tty_flushbuf(30) +#define DTRHIGH() tio_setdtr(0, TRUE) +#define DTRLOW() tio_setdtr(0, FALSE) +#define SENDBREAK() tio_sendbreak() +#define TTYRESET() \ + { \ + tty_abort = 0; \ + tty_status = TTY_SUCCESS; \ + } +#define TTYSTATUS(a) \ + { \ + tty_online = a; \ + tty_hangup = 0; \ + tty_abort = 0; \ + tty_status = TTY_SUCCESS; \ + } + +/* + * io_unix_tty.c + */ +int tty_select(bool *rd, bool *wr, int timeout); +int tty_xselect(bool *rd, bool *wr, int timeout); +int tty_charwait(int timeout); +int tty_read(unsigned char *buf, size_t size); +int tty_read_timeout(unsigned char *buf, size_t size, int timeout); +int tty_write(const unsigned char *buf, size_t size); +int tty_write_timeout(const unsigned char *buf, size_t size, int timeout); +int tty_putc(unsigned char ch, int timeout); +int tty_puts(const unsigned char *s, int timeout); +int tty_getc(int timeout); +int tty_bufc(unsigned char ch, int timeout); +int tty_flushout(void); +int tty_flushbuf(int timeout); +int tty_clearin(void); +int tty_clearout(void); +const char *tty_errstr(int status); + +/* + * io_unix_lock.c + */ +#define LOCKCHECK_NOLOCK 0 +#define LOCKCHECK_LOCKED 1 +#define LOCKCHECK_ERROR 2 +#define LOCKCHECK_OURLOCK 3 + +int port_checklock(const char *lockdir, const s_modemport *modemport); +int port_lock(const char *lockdir, const s_modemport *modemport); +int port_unlock(const char *lockdir, const s_modemport *modemport); + +/* + * io_unix_tio.c + */ +#ifdef HAVE_TERMIOS_H +typedef struct termios TIO; +#endif + +/* + * Flow control flags + */ +#define FLOW_HARD 0x01 +#define FLOW_SOFT 0x02 + +/* + * Define our own RS232 line flags + */ +#ifdef TIOCM_DTR +# define TIO_RS232_DTR TIOCM_DTR +# define TIO_RS232_DSR TIOCM_DSR +# define TIO_RS232_RTS TIOCM_RTS +# define TIO_RS232_CTS TIOCM_CTS +# ifdef TIOCM_CAR +# define TIO_RS232_DCD TIOCM_CAR +# else +# define TIO_RS232_DCD TIOCM_CD +# endif +# ifdef TIOCM_RNG +# define TIO_RS232_RNG TIOCM_RNG +# else +# define TIO_RS232_RNG TIOCM_RI +# endif +#else /* TIOCM_DTR */ +# define TIO_RS232_DTR 0x01 +# define TIO_RS232_DSR 0x02 +# define TIO_RS232_RTS 0x04 +# define TIO_RS232_CTS 0x08 +# define TIO_RS232_DCD 0x10 +# define TIO_RS232_RNG 0x20 +#endif /* TIOCM_DTR */ + +int tio_get(int fd, TIO *tio); +int tio_set(int fd, TIO *tio); +int tio_set_speed(TIO *tio, unsigned int speed); +int tio_get_speed(TIO *tio); +int tio_set_flow_control(int fd, TIO *tio, int flow); +void tio_set_raw_mode(TIO *tio); +void tio_set_local(TIO *tio, bool local); +int tio_set_dtr(int fd, bool on); +int tio_ctty(int fd); +int tio_send_break(void); +int tio_get_dcd(int fd); +int tio_get_rs232_state(void); + +/* + * io_tcpip.c + */ +int tcpip_connect(const char *hostname, e_tcpmode tcpmode); +int tcpip_init(void); +int tcpip_shutdown(void); +bool tcpip_isgood_host(const char *str); + +/* + * io_unix_modem.c + */ +char *port_get_name(const char *devname); +int port_open(const s_modemport *port, int detach, TIO *oldtio); +int port_init(int fd, int portspeed, TIO *oldtio, bool local); +int port_carrier(int fd, bool online); +int port_deinit(int fd, TIO *oldtio); +void port_close(void); + +/* + * io_modem.c + */ +#define MODEM_OK 0 +#define MODEM_ERROR 1 +#define MODEM_CANTSEND 2 +#define MODEM_NORESP 3 + +extern const char *modem_errlist[]; + +long modem_getconnspeed(const char *connstr); +bool modem_isgood_phone(const char *str); +char *modem_transphone(char *buffer, const char *phone, size_t buflen); +void modem_clearin(int timeout); +int modem_putstr(const char *str); +int modem_getline(char *buf, int bufsize, time_t timer); +int modem_dial(const char *dialstr, int timeout, char **connstr); +int modem_command(const char *command, int timeout, bool logit); +int modem_hangup(const char *command, int timeout); +bool modem_candialout(const char *modemdev); +s_modemport *modem_getfree_port(const char *lockdir); +s_modemport *modem_getmatch_port(const char *ttysubname); + +#endif /* _IO_H_ */ diff --git a/source/include/logger.h b/source/include/logger.h new file mode 100644 index 0000000..fbb11ac --- /dev/null +++ b/source/include/logger.h @@ -0,0 +1,85 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _LOGGER_H_ +#define _LOGGER_H_ + +#include "confread.h" + +/* enable this to use syslog facility */ + +#define USE_SYSLOG + + + +enum { LOG_MODE_FILE, LOG_MODE_SYSLOG, LOG_MODE_MIXED }; + +enum { LOG_FILE_DAEMON, LOG_FILE_SESSION, LOG_FILE_DEBUG, LOG_FILE_HISTORY }; + +enum { + LOG_EMERG = 0, /* system is unusable */ + LOG_ALERT = 1, /* action must be taken immediately */ + LOG_CRIT = 2, /* critical conditions */ + LOG_ERR = 3, /* error conditions */ + LOG_WARNING = 4, /* warning conditions */ + LOG_NOTICE = 5, /* normal but significant condition */ + LOG_INFO = 6, /* informational */ + LOG_DEBUG = 7 /* debug-level messages */ +}; + +#ifdef DEBUG +# define D_CONFIG 0x0000001L +# define D_OVERRIDE 0x0000002L +# define D_EVENT 0x0000004L +# define D_NODELIST 0x0000008L +# define D_OUTBOUND 0x0000010L +# define D_INFO 0x0000020L +# define D_HSHAKE 0x0000040L +# define D_TTYIO 0x0000080L +# define D_MODEM 0x0000100L +# define D_PROT 0x0000200L +# define D_FREQ 0x0000400L +# define D_STATEM 0x0000800L +# define D_DAEMON 0x0001000L +# define D_FULL 0xfffffffL +#endif + +#ifdef DEBUG +# define DEB(what) debug what +#else +# define DEB(what) +#endif + +const char *log_getfilename(int whatfor); +bool log_isopened(void); +/* #ifndef USE_SYSLOG +void log_setident(const char *ident); +#endif */ /* ifndef USE_SYSLOG */ +int log_open(const char *logname, const char *ext, const char *tty); +int log_close(void); +int log_reopen(const char *logname, const char *ext, const char *tty); +int log(const char *s, ...); +int logerr(const char *s, ...); + +#ifdef DEBUG +void debug_setlevel(long newlevel, bool logit); +bool debug_isopened(void); +void debug_setfilename(const char *debugname); +int debug_parsestring(char *str, unsigned long *deblevel); +int debug_open(const char *debugname); +int debug_close(void); +int debug(unsigned long what, const char *str, ...); +#endif + +#endif + diff --git a/source/include/nodelist.h b/source/include/nodelist.h new file mode 100644 index 0000000..4bf46af --- /dev/null +++ b/source/include/nodelist.h @@ -0,0 +1,168 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _NODELIST_H_ +#define _NODELIST_H_ + +/* + * Each nodelist has corresponding index file. Index file name is the + * same as nodelist, but extension is changed to the ".bni", so index + * file to the nodelist "net5020.ndl" will be called "net5020.bni" + * + * Nodelist index header: + * + * Offset Size Description + * ------------------------------- + * 0x0000 4 bytes Nodelist file date + * 0x0004 4 bytes Nodelist file size + * 0x0008 4 bytes Total number of entries in index file + * 0x000c 4 bytes Unused + * + * Nodelist index is an array of next entries: + * + * Offset Size Description + * ------------------------------- + * 0x0010 2 bytes Zone number + * 0x0012 2 bytes Net number + * 0x0014 2 bytes Node number + * 0x0016 2 bytes Point number + * 0x0018 2 bytes HUB number (I hope HUB is in the same zone:net) + * 0x001a 4 bytes Offset of string in nodelist file + * + */ + +enum +{ + NODELIST_HDRSIZE = 16, /* Don't change! */ + NODELIST_ENTRYSIZE = 14, /* Don't change! */ + NODELIST_READAHEAD = 50 +}; + +/* + * Modes for nodelist_opendindex() + */ +enum nodelist_iomode +{ + NODELIST_READ, + NODELIST_WRITE +}; + +/* + * Positions of <...> in nodelist strings + */ +enum nodelist_positon +{ + NODELIST_POSKEYWORD = 0, + NODELIST_POSNUMBER = 1, + NODELIST_POSNAME = 2, + NODELIST_POSLOCATION = 3, + NODELIST_POSSYSOP = 4, + NODELIST_POSPHONE = 5, + NODELIST_POSSPEED = 6, + NODELIST_POSFLAGS = 7 +}; + +/* + * Storage sizes for node structure + */ +enum nodelist_limit +{ + BNI_MAXNAME = 48, + BNI_MAXLOCATION = 48, + BNI_MAXSYSOP = 48, + BNI_MAXPHONE = 48, + BNI_MAXFLAGS = 120 +}; + +/* + * node->keyword values + */ +enum nodelist_keyword +{ + KEYWORD_EMPTY, + KEYWORD_ZONE, + KEYWORD_REGION, + KEYWORD_HOST, + KEYWORD_HUB, + KEYWORD_PVT, + KEYWORD_HOLD, + KEYWORD_DOWN, + KEYWORD_BOSS, + KEYWORD_POINT +}; + +/* + * Nodelist procedures error codes + */ +enum nodelist_error +{ + BNIERR_NOERROR = 0, + BNIERR_NODENOTFOUND = 1, + BNIERR_IDXIOERR = 2, + BNIERR_NDLIOERR = 3, + BNIERR_BADINDEX = 4, + BNIERR_NONODELIST = 5 +}; + +typedef struct nodelist +{ + FILE *fp_index; + FILE *fp_nodelist; + char name_index[BF_MAXPATH+1]; + char name_nodelist[BF_MAXPATH+1]; + long entries; +} +s_nodelist; + +typedef struct bni +{ + int zone; + int net; + int node; + int point; + int hub; + long offset; +} +s_bni; + +typedef struct node +{ + s_faddr addr; + s_faddr addr_hub; + enum nodelist_keyword keyword; + bool listed; + char name[BNI_MAXNAME+1]; + char location[BNI_MAXLOCATION+1]; + char sysop[BNI_MAXSYSOP+1]; + char phone[BNI_MAXPHONE+1]; + long speed; + char flags[BNI_MAXFLAGS+1]; + s_timevec worktime; +} +s_node; + +int nodelist_checkflag(const char *nodeflags, const char *flag); +int nodelist_keywordval(const char *keyword); +int nodelist_parsestring(s_node *node, char *str); +s_nodelist *nodelist_open(const char *dir, const char *name, int mode); +int nodelist_checkheader(s_nodelist *nlp); +int nodelist_createheader(s_nodelist *nlp); +int nodelist_close(s_nodelist *nlp); +int nodelist_putindex(s_nodelist *nlp, const s_bni *bni); +int nodelist_findindex(s_nodelist *nlp, s_bni *bni, s_faddr addr); +int nodelist_getstr(s_nodelist *nlp, size_t offset, char *buffer, size_t buflen); +int nodelist_lookup_string(char *buffer, size_t buflen, s_faddr addr); +int nodelist_lookup(s_node *node, s_faddr addr); +void nodelist_initnode(s_node *node, s_faddr addr); + +#endif /* _NODELIST_H_ */ diff --git a/source/include/os.h b/source/include/os.h new file mode 100644 index 0000000..dd86b33 --- /dev/null +++ b/source/include/os.h @@ -0,0 +1,72 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _OS_H_ +#define _OS_H_ + +#define EXEC_OPT_NOWAIT 0x01 +#define EXEC_OPT_SETSID 0x02 +#define EXEC_OPT_LOGOUT 0x04 +#define EXEC_OPT_USESHELL 0x08 + +#define EXEC_MAX_NUM_ENVS 40 +#define EXEC_MAX_NUM_ARGS 20 +#define EXEC_DEFAULT_UMASK ~(S_IRUSR|S_IWUSR); + +struct exec_options +{ + /* + * This variables must be set before running + */ + char *command; + char *envp[EXEC_MAX_NUM_ENVS+1]; + int umask; + int timeout; + int options; + + /* + * This variables will store command execution status + */ + int retc; + int runtime; +}; +typedef struct exec_options s_exec_options; + +int exec_file_exist(const char *command); +void exec_options_init(s_exec_options *eopt); +void exec_options_deinit(s_exec_options *eopt); +void exec_env_add(s_exec_options *eopt, const char *name, const char *value); +void exec_options_set_command(s_exec_options *eopt, const char *command); +int exec_command(s_exec_options *eopt); + +#if defined(OS2) || defined(W32) +#define DIRSEPCHR '\\' +#define DIRSEPSTR "\\" +#else /* Unices */ +#define DIRSEPCHR '/' +#define DIRSEPSTR "/" +#endif + +size_t getfreespace(const char *path); +int xsystem(const char *command, const char *p_input, const char *p_output); + +#ifndef HAVE_SETPROCTITLE +void setargspace(char *argv[], char *envp[]); +void setproctitle(const char *fmt, ...); +#endif + +#ifndef HAVE_RENAME +int rename(const char *old_name, const char *new_name); +#endif + +#endif /* _OS_H_ */ diff --git a/source/include/outbound.h b/source/include/outbound.h new file mode 100644 index 0000000..ef30754 --- /dev/null +++ b/source/include/outbound.h @@ -0,0 +1,209 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _OUTBOUND_H_ +#define _OUTBOUND_H_ + +#include "nodelist.h" + +#define FLAVOR_NONE 0x000 +#define FLAVOR_HOLD 0x001 +#define FLAVOR_NORMAL 0x002 +#define FLAVOR_DIRECT 0x004 +#define FLAVOR_IMMED 0x008 +#define FLAVOR_CRASH 0x010 + +#define ACTION_NOTHING 0x000 /* Do nothing with file after ses. */ +#define ACTION_UNLINK 0x001 /* Unlink file if send successful */ +#define ACTION_TRUNCATE 0x002 /* Truncate file if send successful */ +#define ACTION_FORCEUNLINK 0x004 /* Unlink file in any case after ses.*/ + +#define TYPE_UNKNOWN 0x000 +#define TYPE_NETMAIL 0x001 +#define TYPE_ARCMAIL 0x002 +#define TYPE_TICFILE 0x004 +#define TYPE_FILEECHO 0x008 +#define TYPE_FILEBOX 0x010 +#define TYPE_FROMFLO 0x020 +#define TYPE_REQUEST 0x040 +#define TYPE_REQANSW 0x080 /* Our answer on incoming file req. */ +#define TYPE_FLOFILE 0x100 +#define TYPE_ASONAME 0x200 /* File with AmigaDOS Style Outbound */ + /* name (e.g. 2.5020.1398.11.out) */ + +#define STATUS_WILLSEND 0 +#define STATUS_SKIP 1 +#define STATUS_SENDING 2 +#define STATUS_SENT 3 + +#define QUEUE_SORT_ADDRESS 0x01 +#define QUEUE_SORT_SIZE 0x02 +#define QUEUE_SORT_REVERSE 0x04 + +typedef struct { + FILE *fp; + char att_path[BFORCE_MAX_PATH+1]; + int att_action; + int att_offs; /* offset of the curent line */ +} s_FLO; + +enum { OUTB_TYPE_BSO, + OUTB_TYPE_DOMAIN, + OUTB_TYPE_ASO, + OUTB_TYPE_FBOX }; + +typedef struct outbound_callback_data { + int (*callback)(struct outbound_callback_data *); + void *dest; + s_faddr addr; + char *path; + int flavor; /* Force this flavor for file */ + unsigned short type; +} s_outbound_callback_data; + +typedef struct filelist { + struct filelist *next; + char *fname; + size_t size; + unsigned short type; + unsigned short status; + unsigned short action; + unsigned short flavor; + short flodsc; +} s_filelist; + +typedef struct flofile { + char *fname; + short flavor; + time_t mtime; +} s_flofile; + +typedef struct fsqueue { + s_flofile *flotab; + s_filelist *fslist; + int flonum; /* Number of items in .?LO files table */ +} s_fsqueue; + +#define TRIES_RESET -1 /* Use this macro to reset tries counter */ +#define HOLD_RESET 1 /* Use this macro to reset hold timer */ + +typedef struct sess_stat { + bool undialable; + int tries; + int tries_noconn; + int tries_nodial; + int tries_noansw; + int tries_hshake; + int tries_sessns; + unsigned long hold_until; + unsigned long hold_freqs; + unsigned long last_success; + unsigned long last_success_in; + unsigned long last_success_out; +} s_sess_stat; + +typedef struct sysentry { + s_node node; + bool lookedup; +const s_override *overrides; /* List of all overrides */ +const s_override *lineptr; /* List of all overrides */ + s_sess_stat stat; + int line; /* Current line number */ + bool tcpip; /* Call to the current line via TCP/IP? */ + bool busy; /* Address is busy [in an another queue, etc.] */ + time_t lastcall; /* Last call _finish_ time */ + time_t mailage; /* The oldest file modification time */ + size_t netmail_size; + size_t arcmail_size; + size_t request_size; + size_t files_size; + int flavors; + int types; +} s_sysentry; + +typedef struct sysqueue { + s_sysentry *systab; + int sysnum; + time_t holduntil; + int current_modem; + int current_tcpip; + int next_modem; + int next_tcpip; +} s_sysqueue; + +typedef struct exttab { +const char *ext; + int type; + int flavor; + int action; +} s_exttab; + +extern s_exttab outtab[]; +extern s_exttab exttab[]; +extern int (*sysqueue_add_callback)(s_sysentry *); +extern int (*sysqueue_rem_callback)(s_sysentry *); +extern bool sysqueue_dont_count_sizes; + +/* outb_bsy.c */ +int out_bsy_check(s_faddr addr); +#ifdef BFORCE_USE_CSY +int out_bsy_lock(s_faddr addr, bool csy_locks); +#else +int out_bsy_lock(s_faddr addr); +#endif +int out_bsy_unlock(s_faddr addr); +int out_bsy_unlockall(void); + +/* outb_flo.h */ +s_FLO *flo_open(const char *path, const char *mode); +int flo_next(s_FLO *FLO); +int flo_mark_sent(s_FLO *FLO); +int flo_eof(s_FLO *FLO); +int flo_close(s_FLO *FLO); +bool out_flo_isempty(const char *path); +int out_flo_marksent(const char *fname, const char *floname); +int out_flo_getsizes(const char *floname, size_t *arcmail, size_t *files); +int out_flo_unlinkempty(const s_flofile *flotab, int flonum); + +/* outb_getname.c */ +char *out_getname_4d(s_faddr addr); +char *out_getname_domain(s_faddr addr); +char *out_getname_amiga(s_faddr addr); + +/* outb_queue.c */ +int out_filetype(const char *fname); +int out_handle_fsqueue(s_outbound_callback_data *callback); +void deinit_filelist(s_filelist *filelist); +void deinit_fsqueue(s_fsqueue *q); +#ifdef DEBUG +void log_filelist(const s_filelist *filelist); +void log_fsqueue(const s_fsqueue *q); +#endif + +/* outb_main.c */ +int out_get_root(const char *outbound, char **out_root, char **out_main); +int out_parse_name_aso(s_faddr *addr, const char *name); +int out_scan(s_outbound_callback_data *callback, const s_falist *fa_list); + +/* outb_sysqueue.c */ +void out_reset_trycounters(s_sysentry *syst); +void out_reset_sysqueue(s_sysqueue *q); +void out_sysqueue_sort(s_sysqueue *q, int opts); +void out_remove_from_sysqueue(s_sysqueue *q, int pos); +int out_handle_sysqueue(s_outbound_callback_data *callback); +void deinit_sysqueue(s_sysqueue *q); +#ifdef DEBUG +void log_sysqueue(const s_sysqueue *q); +#endif + +#endif diff --git a/source/include/prot_binkp.h b/source/include/prot_binkp.h new file mode 100644 index 0000000..241efb7 --- /dev/null +++ b/source/include/prot_binkp.h @@ -0,0 +1,160 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + * + * binkp's frames: + * + * +---------------------- 0=data block, 1=message(command) + * | +---- data block size / msg's argument size + * | | + * 7 6543210 76543210 + * +-+-------+--------+--- ... ---+ + * | | HI LO | | -- data block / msg's argument + * +-+-------+--------+--- ... ---+ + */ + +#ifndef _P_BINKP_H_ +#define _P_BINKP_H_ + +#define BINKP_NAME "binkp" +#define BINKP_MAJOR 1 +#define BINKP_MINOR 0 +#define BINKP_PORT 24554 +#define BINKP_TIMEOUT (5*60) +#define BINKP_MIN_BLKSIZE 128 +#define BINKP_MAX_BLKSIZE 0x7fff +#define BINKP_DEF_BLKSIZE (4*1024u) +#define BINKP_BLK_HDRSIZE 2 + +#define BINKP_MAXPASSWD 64 +#define BINKP_MAXSYSTNAME 120 +#define BINKP_MAXLOCATION 120 +#define BINKP_MAXSYSOP 120 +#define BINKP_MAXPHONE 120 +#define BINKP_MAXFLAGS 120 +#define BINKP_MAXLOCATION 120 +#define BINKP_MAXPROGNAME 40 +#define BINKP_MAXPROTNAME 40 +#define BINKP_MAXTIMESTR 40 +#define BINKP_MAXCHALLENGE 128 +#define BINKP_MAXOPT 196 + +#define BINKP_OPT_NR 0x01 /* Non-reliable mode */ +#define BINKP_OPT_MB 0x02 /* Multiple batch mode */ +#define BINKP_OPT_MPWD 0x04 /* Multiple passwods mode */ +#define BINKP_OPT_MD5 0x08 /* CRAM-MD5 authentication */ +#define BINKP_OPT_SHA1 0x10 /* CRAM-SHA1 authentication */ +#define BINKP_OPT_DES 0x20 /* CRAM-DES authentication */ + +typedef struct { + s_sysaddr *addrs; + int anum; + char passwd[BINKP_MAXPASSWD+1]; + char systname[BINKP_MAXSYSTNAME+1]; + char location[BINKP_MAXLOCATION+1]; + char sysop[BINKP_MAXSYSOP+1]; + char phone[BINKP_MAXPHONE+1]; + char flags[BINKP_MAXFLAGS+1]; + char progname[BINKP_MAXPROGNAME+1]; + char protname[BINKP_MAXPROTNAME+1]; + char timestr[BINKP_MAXTIMESTR+1]; + char opt[BINKP_MAXOPT+1]; + int majorver; + int minorver; + int options; + char challenge[BINKP_MAXCHALLENGE+1]; + int challenge_length; +} s_binkp_sysinfo; + + +typedef enum { + /* + * Pseudo message types, returned by binkp_recv() + */ + BPMSG_EXIT = -3, /* Terminate session */ + BPMSG_NONE = -2, /* Got nothing intresting */ + BPMSG_DATA = -1, /* Got data block */ + /* + * Real BinkP message types + */ + BPMSG_NUL = 0, /* Site information */ + BPMSG_ADR, /* List of addresses */ + BPMSG_PWD, /* Session password */ + BPMSG_FILE, /* File information */ + BPMSG_OK, /* Password was acknowleged (data ignored) */ + BPMSG_EOB, /* End Of Batch (data ignored) */ + BPMSG_GOT, /* File received */ + BPMSG_ERR, /* Misc errors */ + BPMSG_BSY, /* All AKAs are busy */ + BPMSG_GET, /* Get a file from offset */ + BPMSG_SKIP, /* Skip a file (RECEIVE LATER) */ + BPMSG_MIN = BPMSG_NUL, /* Minimal message type value */ + BPMSG_MAX = BPMSG_SKIP /* Maximal message type value */ +} e_bpmsg; + + +typedef struct { + bool sent; /* Sent message (queued) */ + e_bpmsg type; /* Message type */ + int size; /* Message size (length of text) */ + char *data; /* Message text */ +} s_bpmsg; + + +typedef struct { + char *obuf; /* Output buffer */ + int opos; /* Unsent bytes left in buffer */ + char *optr; /* Send data from this position */ + + char *ibuf; /* Our input buffer */ + int ipos; + int isize; + bool imsg; /* Is it message? */ + bool inew; + e_bpmsg imsgtype; /* Message type */ + + int junkcount; + s_bpmsg *msgqueue; /* Outgoing messages queue */ + int n_msgs; /* Number of messages in queue */ + + int timeout; +} s_bpinfo; + +/* prot_binkp.c */ +int binkp_outgoing(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data); +int binkp_incoming(s_binkp_sysinfo *local_data, s_binkp_sysinfo *remote_data); +int binkp_transfer(s_protinfo *pi); + +/* prot_binkp_misc.c */ +void binkp_init_bpinfo(s_bpinfo *bpi); +void binkp_deinit_bpinfo(s_bpinfo *bpi); +int binkp_gethdr(const char *s); +int binkp_getmsgtype(char ch); +void binkp_puthdr(char *s, unsigned int u); +void binkp_putmsgtype(char *s, e_bpmsg msg); +void binkp_queuemsg(s_bpinfo *bpi, e_bpmsg msg, const char *s1, const char *s2); +void binkp_queuemsgf(s_bpinfo *bpi, e_bpmsg msg, const char *fmt, ...); +int binkp_parsfinfo(char *s, char **fn, size_t *sz, time_t *tm, size_t *offs); +int binkp_buffer_message(s_bpinfo *bpi, s_bpmsg *msg); +int binkp_send_buffer(s_bpinfo *bpi); +int binkp_send(s_bpinfo *bpi); +int binkp_flush_queue(s_bpinfo *bpi, int timeout); +int binkp_recv(s_bpinfo *bpi); +void binkp_update_sysinfo(s_binkp_sysinfo *binkp); +void binkp_log_sysinfo(s_binkp_sysinfo *binkp); +void binkp_queue_sysinfo(s_bpinfo *bpi, s_binkp_sysinfo *binkp); +void binkp_set_sysinfo(s_binkp_sysinfo *binkp, s_faddr *remote_addr, bool caller); +void binkp_parse_options(s_binkp_sysinfo *binkp, char *options); + +/* prot_binkp_api.c */ +extern s_handshake_protocol handshake_protocol_binkp; + +#endif /* _P_BINKP_H_ */ diff --git a/source/include/prot_common.h b/source/include/prot_common.h new file mode 100644 index 0000000..a4f99d0 --- /dev/null +++ b/source/include/prot_common.h @@ -0,0 +1,136 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _P_COMMON_H_ +#define _P_COMMON_H_ + +#include "outbound.h" + +/* File transfer protocols return codes */ +#define PRC_NOERROR 0 /* No comments :) */ +#define PRC_ERROR 1 /* I/O error occured while snd./rcv. */ +#define PRC_REMOTEABORTED 2 /* "ABORT" initiated by remote */ +#define PRC_LOCALABORTED 3 /* We got SIGINT/SIGTERM? */ +#define PRC_CPSTOOLOW 4 /* Cps was so low.. :( */ +#define PRC_STOPTIME 5 /* Aborted due to the time limits */ + +/* Send/Recv file status values */ +#define FSTAT_PROCESS 1 +#define FSTAT_WAITACK 2 +#define FSTAT_SUCCESS 3 +#define FSTAT_SKIPPED 4 +#define FSTAT_REFUSED 5 + +typedef struct traffic { + int netmail_num; /* Number of netmail packets */ + int netmail_time; /* Netmail packets sending/receiving time */ + size_t netmail_size; /* Size of netmail packtes */ + int arcmail_num; /* Dito.. */ + int arcmail_time; + size_t arcmail_size; + int files_num; + int files_time; + size_t files_size; + int freqed_num; + int freqed_time; + size_t freqed_size; +} s_traffic; + +/* + * Information on currently receiveing/transmitting file + */ +typedef struct finfo { + FILE *fp; /* File descriptor of current file */ + char *local_name; /* Local file name that is used at our side */ + char *net_name; /* File name as it known to the remote side */ + char *fname; /* Local file name with full path */ + time_t start_time; /* Start of current file rx/tx transactions */ + time_t mod_time; /* File last modification time */ + mode_t mode; + size_t bytes_total; /* File size */ + size_t bytes_sent; + size_t bytes_received; + size_t bytes_skipped; /* crash recovery */ + int eofseen; /* end of file seen */ + int status; + int action; + int type; + int flodsc; /* Index number in flo files table */ +} s_finfo; + +/* + * Transfer protocol related structure + */ +typedef struct protinfo { + /* ----------------------------------------------------------------- */ + /* Variables defined before protocol starting */ + /* ----------------------------------------------------------------- */ + bool reqs_only; /* Send only .REQ files (for Hydra RH1 mode) */ + time_t stop_time; /* Stop transfer at this time */ + int freq_timelimit; /* Abort transfer if send freqs longer this */ + int min_tx_cps; /* Minimal transmite speed */ + int min_rx_cps; /* Minimal receive speed */ + int min_cps_time; /* Abort transfer if minimal bps stay during + this time period */ + char *buffer; /* Ptr. to buffer for buffered file saving */ + size_t buflen; /* Buffer size */ + /* ----------------------------------------------------------------- */ + /* All variables below used by misc protocol routines */ + /* ----------------------------------------------------------------- */ + s_filelist *filelist; /* List of files.. It is our answer on .req! */ + int tx_cps; /* Current transmite CPS */ + int rx_cps; /* Current receive CPS */ + int send_freqtime; /* Time we spend at sending REQed files */ + time_t tx_low_cps_time; /* If CPS lower min_tx_cps it is time how + long it lasts */ + time_t rx_low_cps_time; /* Same, but for transmite CPS */ + time_t start_time; /* Time transfer started at */ + + s_traffic traffic_sent; + s_traffic traffic_rcvd; + size_t send_left_size; + size_t recv_left_size; + int send_left_num; + int recv_left_num; + + s_finfo *send; + s_finfo *recv; + s_finfo *sentfiles; + s_finfo *rcvdfiles; + int n_sentfiles; + int n_rcvdfiles; +} s_protinfo; + +extern const char *Protocols[]; /* Protocol names */ + +int p_tx_fopen(s_protinfo *pi); +int p_tx_fclose(s_protinfo *pi); +int p_tx_readfile(char *buf, size_t sz, s_protinfo *pi); +int p_rx_writefile(const char *buf, size_t sz, s_protinfo *pi); +int p_compfinfo(s_finfo *finf, const char *fn, size_t sz, time_t tm); +int p_rx_fopen(s_protinfo *pi, char *f_name, size_t f_size, time_t f_modtime, mode_t f_mode); +int p_rx_fclose(s_protinfo *pi); +int p_info(s_protinfo *pi, int bidir); +void prot_update_traffic(s_protinfo *pi, const s_fsqueue *q); +void p_log_txrxstat(const s_protinfo *pi); +void p_session_cleanup(s_protinfo *pi, bool success); +void p_shortname(char *name); +char *prot_unique_name(char *dirname, char *fname, int type); +void p_checkname(char *name); +void deinit_finfo(s_finfo *fi); +void init_protinfo(s_protinfo *pi, bool caller); +void deinit_protinfo(s_protinfo *pi); +char *p_convfilename(const char *origname, int type); +char *p_gettmpname(const char *inbound, char *fname, s_faddr addr, size_t sz, time_t tm); + +#endif diff --git a/source/include/prot_emsi.h b/source/include/prot_emsi.h new file mode 100644 index 0000000..5a7a07f --- /dev/null +++ b/source/include/prot_emsi.h @@ -0,0 +1,221 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _S_EMSI_H_ +#define _S_EMSI_H_ + +/* + * EMSI limits + */ +#define EMSI_MAXDAT 16384 +#define EMSI_MAXNFLAG 20 +#define EMSI_MAXPASSWD 30 +#define EMSI_MAXMPID 30 +#define EMSI_MAXMNAME 120 +#define EMSI_MAXMVER 120 +#define EMSI_MAXMREG 120 +#define EMSI_MAXSYSNAME 120 +#define EMSI_MAXLOCATION 120 +#define EMSI_MAXSYSOP 120 +#define EMSI_MAXPHONE 120 +#define EMSI_MAXFLAGS 120 +#define EMSI_MAXOHTIME 120 +#define EMSI_MAXFRTIME 120 +#define EMSI_MAXXDATETIME 60 +#define EMSI_MAXADDONS 120 + +/* + * EMSI XXn flags that affect only address number n in AKA list + */ +#define EMSI_FLAG_PU 0x0001 /* Pickup FILES for this address */ +#define EMSI_FLAG_HA 0x0002 /* Hold all FILES for this address */ +#define EMSI_FLAG_PM 0x0004 /* PickUp Mail ONLY for this address */ +#define EMSI_FLAG_NF 0x0008 /* No TIC'S, associated files or file attaches */ + /* for this address */ +#define EMSI_FLAG_NX 0x0010 /* No compressed mail pickup desired, */ + /* for this address */ +#define EMSI_FLAG_NR 0x0020 /* File requests not accepted by caller */ + /* for this address */ +#define EMSI_FLAG_HN 0x0040 /* Hold all traffic EXCEPT Mail (ARCmail and */ + /* Packets) for this address */ +#define EMSI_FLAG_HX 0x0080 /* Hold compressed mail for this address */ +#define EMSI_FLAG_HF 0x0100 /* Hold tic's and associated files and file */ + /* attaches other than mail for this address */ +#define EMSI_FLAG_HR 0x0200 /* Hold file requests (not processed at this */ + /* time)for this address */ + +/* + * Defines for state machine + */ +#define SME -1 +#define SM0 0 +#define SM1 1 +#define SM2 2 +#define SM3 3 +#define SM4 4 +#define SM5 5 +#define SM6 6 +#define SM7 7 +#define SM8 8 +#define SM9 9 + +struct states +{ +const char *st_name; + int (*proc)(); +}; +typedef struct states s_states; + +struct linkcodes +{ + /* + * EMSI-I (FSC-0056) and EMSI-II (FSC-0088) flags + * for XXn flags see s_emsiaddr structure + */ + + UINT32 N81:1, /* Communication parameter emulation :) (EMSI-I) */ + PUP:1, /* Pickup FILES for primary address only */ + PUA:1, /* Pickup FILES for all presented addresses */ + NPU:1, /* No FILE pickup desired. (calling system) */ + HAT:1, /* Hold all FILES (answering system) */ + PMO:1, /* PickUp Mail (ARCmail and Packets) ONLY */ + NFE:1, /* No TIC'S, associated files or files attaches */ + /* desired */ + NXP:1, /* No compressed mail pickup desired */ + NRQ:1, /* File requests not accepted by caller */ + /* This flag is presented if file request processing */ + /* is disabled TEMPORARILY for any reason */ + HNM:1, /* Hold all traffic EXCEPT Mail(ARCmail and Packets) */ + HXT:1, /* Hold compressed mail traffic. */ + HFE:1, /* Hold tic's and associated files */ + /* and file attaches other than mail */ + HRQ:1, /* Hold file requests (not processed at this time) */ + /* this flag is presented if file request processing */ + /* is disabled TEMPORARILY for any reason */ + FNC:1, /* Convert file names to "msdos" format */ + RMA:1, /* System is able to process multiple file requests */ + RH1:1; /* Under Hydra batch 1 contain file requests only, */ + /* while batch 2 is reserved for all other files */ +}; +typedef struct linkcodes s_linkcodes; + +struct compcodes +{ + UINT16 NCP:1, /* No compatible protocols (failure) */ + ZMO:1, /* Zmodem w/1,024 byte data packets */ + ZAP:1, /* ZedZap (Zmodem variant) */ + DZA:1, /* DirectZAP (Zmodem variant) */ + JAN:1, /* Janus */ + HYD:1; /* Hydra */ + + UINT16 FRQ:1, /* The system will accept and process FREQs */ + NRQ:1, /* No file requests accepted by this system */ + ARC:1, /* ARCmail 0.60-capable */ + XMA:1, /* Supports other forms of compressed mail */ + FNC:1, /* Filename conversion into 8.3 format */ + EII:1, /* EMSI-II flags are supported */ + DFB:1, /* Can fall-back to FTS1/WAZOO negotiation */ + CHT:1, /* Chat during transmittion available */ + BBS:1, /* Site has public BBS available */ + HFR:1; /* Remote will automaticaly hold requested */ + /* files for us */ +}; +typedef struct compcodes s_compcodes; + +struct emsi +{ + /* + * Keep here all unknown EMSI_DAT addons + */ + char addons[EMSI_MAXADDONS+1]; + + /* + * {EMSI_DAT} (main handshake information) + */ + bool have_emsi; + s_sysaddr *addrs; /* dynamicaly allocated array */ + int anum; /* number of used entries in it */ + char passwd[EMSI_MAXPASSWD+1]; + s_linkcodes linkcodes; /* XXn linkcodes contained in eaddr */ + s_compcodes compcodes; + char m_pid[EMSI_MAXMPID+1]; + char m_name[EMSI_MAXMNAME+1]; + char m_ver[EMSI_MAXMVER+1]; + char m_reg[EMSI_MAXMREG+1]; + + /* + * {IDENT} (system information) + */ + bool have_ident; + char sname[EMSI_MAXSYSNAME+1]; + char location[EMSI_MAXLOCATION+1]; + char sysop[EMSI_MAXSYSOP+1]; + char phone[EMSI_MAXPHONE+1]; + int speed; + char flags[EMSI_MAXFLAGS+1]; + + /* + * {TRAF} (size of netmail and arcmail files on hold) + */ + bool have_traf; + size_t netmail_size; + size_t arcmail_size; + + /* + * {MOH#} (size of files on hold? :)) + */ + bool have_moh; + size_t files_size; + + /* + * {OHFR} (site's work and freq time intervals) + */ + bool have_ohfr; + char oh_time[EMSI_MAXOHTIME+1]; + char fr_time[EMSI_MAXFRTIME+1]; + + /* + * {TZUTC} (site's time zone) + */ + bool have_tzutc; + int tzutc; + + /* + * {XDATETIME} (site's date and time in extended format) + */ + bool have_xdatetime; + char xdatetime[EMSI_MAXXDATETIME+1]; + + /* + * {TRX#} (site's current time) + */ + bool have_trx; + time_t time; +}; +typedef struct emsi s_emsi; + +/* prot_emsi.c */ +int emsi_send_emsidat(s_emsi *local_emsi); +int emsi_recv_emsidat(s_emsi *remote_emsi); +void emsi_set_sysinfo(s_emsi *emsi, s_emsi *remote_emsi, int hrc, + e_protocol protocol); + +/* prot_emsi_api.c */ +extern s_handshake_protocol handshake_protocol_emsi; + +/* prot_emsi_misc.c */ +char *emsi_createdat(s_emsi *emsi); +int emsi_parsedat(char *emsi_dat, s_emsi *emsi); +void emsi_logdat(s_emsi *emsi); + +#endif diff --git a/source/include/prot_yoohoo.h b/source/include/prot_yoohoo.h new file mode 100644 index 0000000..f798983 --- /dev/null +++ b/source/include/prot_yoohoo.h @@ -0,0 +1,64 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _S_YOOHOO_H_ +#define _S_YOOHOO_H_ + +#define YOOHOO_HELLOLEN 128 /* Size of the 'HELLO' frame */ +#define YOOHOO_MAXFIELD 40 + +/* + * Information for/from yoohoo handshake (real packet size is 128 bytes) + */ +typedef struct +{ + s_sysaddr *addrs; /* FTN address */ + int anum; + int product_code; /* product code */ + int version_maj; /* major revision of the product */ + int version_min; /* minor revision of the product */ + char system[YOOHOO_MAXFIELD+1]; + char sysop[YOOHOO_MAXFIELD+1]; + char passwd[YOOHOO_MAXFIELD+1]; + int capabilities; +} +s_yoohoo_sysinfo; + +#define YOOHOO_DIETIFNA 0x0001 /* Can do fast "FTS-0001" */ +#define YOOHOO_FTB_USER 0x0002 /* Reserved by Opus-CBCS */ +#define YOOHOO_ZMODEM 0x0004 /* Does ZModem, 1K blocks */ +#define YOOHOO_ZEDZAP 0x0008 /* Can do ZModem variant */ +#define YOOHOO_JANUS 0x0010 /* Can do Janus */ +#define YOOHOO_HYDRA 0x0020 /* Can do Hydra */ +#define YOOHOO_Bit_6 0x0040 /* reserved by FTSC */ +#define YOOHOO_Bit_7 0x0080 /* reserved by FTSC */ +#define YOOHOO_Bit_8 0x0100 /* reserved by FTSC */ +#define YOOHOO_Bit_9 0x0200 /* reserved by FTSC */ +#define YOOHOO_Bit_a 0x0400 /* reserved by FTSC */ +#define YOOHOO_Bit_b 0x0800 /* reserved by FTSC */ +#define YOOHOO_Bit_c 0x1000 /* reserved by FTSC */ +#define YOOHOO_Bit_d 0x2000 /* reserved by FTSC */ +#define YOOHOO_DO_DOMAIN 0x4000 /* Packet contains domain */ +#define YOOHOO_WZ_FREQ 0x8000 /* WZ file req. ok */ + +/* prot_yoohoo.c */ +int yoohoo_send_hello(s_yoohoo_sysinfo *local_data); +int yoohoo_recv_hello(s_yoohoo_sysinfo *remote_data); +void yoohoo_set_sysinfo(s_yoohoo_sysinfo *local_data, int hrc, + e_protocol protocol); +void yoohoo_log_sysinfo(s_yoohoo_sysinfo *yoohoo); + +/* prot_yoohoo_api.c */ +extern s_handshake_protocol handshake_protocol_yoohoo; + +#endif diff --git a/source/include/prot_zmodem.h b/source/include/prot_zmodem.h new file mode 100644 index 0000000..6f91dcc --- /dev/null +++ b/source/include/prot_zmodem.h @@ -0,0 +1,222 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + * + * Z M O D E M . H Manifest constants for ZMODEM + * application to application file transfer protocol + * 05-23-87 Chuck Forsberg Omen Technology Inc + */ + +#ifndef _P_ZMODEM_H_ +#define _P_ZMODEM_H_ + +#include "prot_common.h" + +/* ------------------------------------------------------------------------- */ +/* Z-Modem chracteristics definitions */ +/* ------------------------------------------------------------------------- */ +#define ZDEADTIMER 180 /* If expired think remote side is dead */ +#define ZRXTIMEOUT 120 /* Time to wait for receiving whole block */ +#define ZWAITTIME 30 /* Time to wait for character */ +#define ZMAXBLOCKLEN 8192 /* Maximal zmodem RX/TX block size */ +#define ZMAXTRIES 10 /* Maximal number of tries to do somthing */ +#define ZRXSKIPFIN 2 /* Number of ZFINs to ignore at start up */ +#define ZMAXFNAME 4096 /* Max. file name, to avoid txbuf overflow */ + + +/* ------------------------------------------------------------------------- */ +/* Z-Modem constants definition */ +/* ------------------------------------------------------------------------- */ +#define ZPAD '*' /* 052 Padding character begins frames */ +#define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ +#define ZBIN 'A' /* Binary frame indicator */ +#define ZHEX 'B' /* HEX frame indicator */ +#define ZBIN32 'C' /* Binary frame with 32 bit FCS */ + +/* ------------------------------------------------------------------------- */ +/* Frame types (see array "Frametypes" in zm.c) */ +/* ------------------------------------------------------------------------- */ +#define ZCRCERR -5 /* CRC error */ +#define ZERROR -4 /* Miscelaneouse errors */ +#define ZEXIT -3 /* Critical errors */ +#define ZHANGUP -2 /* No Carrier */ +#define ZTIMER -1 /* Time out waiting for smth. */ +#define ZOK 0 /* All right */ +/* + * TTY_TIMEOUT -1 \ + * TTY_HANGUP -2 > defined in ttyio.h + * TTY_ERROR -3 / + */ +#define ZRQINIT 0 /* Request receive init */ +#define ZRINIT 1 /* Receive init */ +#define ZSINIT 2 /* Send init sequence (optional) */ +#define ZACK 3 /* ACK to above */ +#define ZFILE 4 /* File name from sender */ +#define ZSKIP 5 /* To sender: skip this file */ +#define ZNAK 6 /* Last packet was garbled */ +#define ZABORT 7 /* Abort batch transfers */ +#define ZFIN 8 /* Finish session */ +#define ZRPOS 9 /* Resume data trans at this position */ +#define ZDATA 10 /* Data packet(s) follow */ +#define ZEOF 11 /* End of file */ +#define ZFERR 12 /* Fatal Read or Write error Detected */ +#define ZCRC 13 /* Request for file CRC and response */ +#define ZCHALLENGE 14 /* Receiver's Challenge */ +#define ZCOMPL 15 /* Request is complete */ +#define ZCAN 16 /* Other end canned session with CAN*5 */ +#define ZFREECNT 17 /* Request for free bytes on filesystem */ +#define ZCOMMAND 18 /* Command from sending program */ +#define ZSTDERR 19 /* Output to standard error, data follows */ + +/* ------------------------------------------------------------------------- */ +/* ZDLE sequences */ +/* ------------------------------------------------------------------------- */ +#define ZCRCE 'h' /* CRC next, frame ends, header packet follows */ +#define ZCRCG 'i' /* CRC next, frame continues nonstop */ +#define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */ +#define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */ +#define ZRUB0 'l' /* Translate to rubout 0177 */ +#define ZRUB1 'm' /* Translate to rubout 0377 */ + +/* ------------------------------------------------------------------------- */ +/* $zdlread return values (internal) */ +/* -1 is general error, -2 is timeout */ +/* ------------------------------------------------------------------------- */ +#define GOTOR 0400 +#define GOTCRCE (ZCRCE|GOTOR) /* ZDLE-ZCRCE received */ +#define GOTCRCG (ZCRCG|GOTOR) /* ZDLE-ZCRCG received */ +#define GOTCRCQ (ZCRCQ|GOTOR) /* ZDLE-ZCRCQ received */ +#define GOTCRCW (ZCRCW|GOTOR) /* ZDLE-ZCRCW received */ +#define GOTCAN (GOTOR|030) /* CAN*5 seen */ + +/* ------------------------------------------------------------------------- */ +/* Byte positions within header array */ +/* ------------------------------------------------------------------------- */ +#define ZF0 3 /* First flags byte */ +#define ZF1 2 +#define ZF2 1 +#define ZF3 0 +#define ZP0 0 /* Low order 8 bits of position */ +#define ZP1 1 +#define ZP2 2 +#define ZP3 3 /* High order 8 bits of file position */ + +/* ------------------------------------------------------------------------- */ +/* Bit Masks for ZRINIT flags byte ZF0 */ +/* ------------------------------------------------------------------------- */ +#define CANFDX 0x01 /* Rx can send and receive true FDX */ +#define CANOVIO 0x02 /* Rx can receive data during disk I/O */ +#define CANBRK 0x04 /* Rx can send a break signal */ +#define CANCRY 0x08 /* Receiver can decrypt */ +#define CANLZW 0x10 /* Receiver can uncompress */ +#define CANFC32 0x20 /* Receiver can use 32 bit Frame Check */ +#define ESCCTL 0x40 /* Receiver expects ctl chars to be escaped */ +#define ESC8 0x80 /* Receiver expects 8th bit to be escaped */ + +/* ------------------------------------------------------------------------- */ +/* Bit Masks for ZRINIT flags byze ZF1 */ +/* ------------------------------------------------------------------------- */ +#define ZF1_CANVHDR 0x01 /* Variable headers OK */ +#define ZF1_TIMESYNC 0x02 /* nonstandard, Receiver request timesync */ + +/* ------------------------------------------------------------------------- */ +/* Parameters for ZSINIT frame */ +/* ------------------------------------------------------------------------- */ +#define ZATTNLEN 32 /* Max length of attention string */ + +/* ------------------------------------------------------------------------- */ +/* Bit Masks for ZSINIT flags byte ZF0 */ +/* ------------------------------------------------------------------------- */ +#define TESCCTL 0100 /* Transmitter expects ctl chars to be escaped */ +#define TESC8 0200 /* Transmitter expects 8th bit to be escaped */ + +/* ------------------------------------------------------------------------- */ +/* Parameters for ZFILE frame */ +/* Conversion options one of these in ZF0 */ +/* ------------------------------------------------------------------------- */ +#define ZCBIN 1 /* Binary transfer - inhibit conversion */ +#define ZCNL 2 /* Convert NL to local end of line convention */ +#define ZCRESUM 3 /* Resume interrupted file transfer */ + +/* ------------------------------------------------------------------------- */ +/* Management include options, one of these ored in ZF1 */ +/* ------------------------------------------------------------------------- */ +#define ZF1_ZMSKNOLOC 0x80 /* Skip file if not present at rx */ + +/* ------------------------------------------------------------------------- */ +/* Management options, one of these ored in ZF1 */ +/* ------------------------------------------------------------------------- */ +#define ZF1_ZMMASK 0x1f /* Mask for the choices below */ +#define ZF1_ZMNEWL 1 /* Transfer if source newer or longer */ +#define ZF1_ZMCRC 2 /* Transfer if different file CRC or length */ +#define ZF1_ZMAPND 3 /* Append contents to existing file (if any) */ +#define ZF1_ZMCLOB 4 /* Replace existing file */ +#define ZF1_ZMNEW 5 /* Transfer if source newer */ + /* Number 5 is alive ... */ +#define ZF1_ZMDIFF 6 /* Transfer if dates or lengths different */ +#define ZF1_ZMPROT 7 /* Protect destination file */ +#define ZF1_ZMCHNG 8 /* Change filename if destination exists */ + +/* ------------------------------------------------------------------------- */ +/* Transport options, one of these in ZF2 */ +/* ------------------------------------------------------------------------- */ +#define ZTLZW 1 /* Lempel-Ziv compression */ +#define ZTCRYPT 2 /* Encryption */ +#define ZTRLE 3 /* Run Length encoding */ + +/* ------------------------------------------------------------------------- */ +/* Extended options for ZF3, bit encoded */ +/* ------------------------------------------------------------------------- */ +#define ZXSPARS 64 /* Encoding for sparse file operations */ + +/* ------------------------------------------------------------------------- */ +/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */ +/* ------------------------------------------------------------------------- */ +#define ZCACK1 1 /* Acknowledge, then do command */ + +/* ------------------------------------------------------------------------- */ +/* Z-Modem globals */ +/* ------------------------------------------------------------------------- */ +extern int Z_Rxexp; /* True means timer expired */ +extern int Z_Rxtout; /* Seconds to wait for receiving whole block */ +extern int Z_Rxwait; /* Seconds to wait for character available */ +extern int Z_Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame r-ed */ +extern int Z_Rxtype; /* Type of header received */ +extern int Z_Rxcount; /* Count of data bytes received */ +extern int Z_Txnulls; /* Number of nulls to send at beg. of ZDATA */ +extern char Z_Rxhdr[4]; /* Received header */ +extern char Z_Txhdr[4]; /* Transmitted header */ +extern long Z_Rxpos; /* Received file position */ +extern int Z_Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ +extern int Z_Txcrc32; /* Display flag ind. 32 bit CRC being sent */ +extern int Z_Rxcrc32; /* Display flag ind. 32 bit CRC being r-ed */ +extern char Z_Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +extern int Z_Ctlesc; /* Encode control characters */ +extern int Z_Lastsent; /* Character we sent last */ +//extern int Z_Dirzap; /* Direct ZedZap (don't escape XON/XOFF) */ + +/* ------------------------------------------------------------------------- */ +/* Z-Modem primitives (look p_zmmisc.c for them) */ +/* ------------------------------------------------------------------------- */ +void setalarm(int sec); +int zsendline(char c); +int zsbhdr(int type, char *hdr); +int zshhdr(int type, char *hdr); +int zsdata(const char *buf, int length, int frameend, long pos); +int zrdata(char *buf, int length, long pos); +int zgethdr(char *hdr); +void stohdr(char *hdr, long pos); +long rclhdr(char *hdr); + +int tx_zmodem(s_protinfo *pi, bool caller); +int rx_zmodem(s_protinfo *pi, bool caller); + +#endif diff --git a/source/include/session.h b/source/include/session.h new file mode 100644 index 0000000..594427c --- /dev/null +++ b/source/include/session.h @@ -0,0 +1,223 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _S_MAIN_H_ +#define _S_MAIN_H_ + +#define CALLOPT_FORCE 0x01 +#define CALLOPT_INET 0x02 + +#include "io.h" +#include "nodelist.h" +#include "outbound.h" +#include "prot_common.h" + +typedef enum session { + SESSION_UNKNOWN, + SESSION_FTSC, + SESSION_YOOHOO, + SESSION_EMSI, + SESSION_BINKP +} e_session; + +typedef enum protocol { + PROT_NOPROT, + PROT_XMODEM, + PROT_ZMODEM, + PROT_ZEDZAP, + PROT_DIRZAP, + PROT_JANUS, + PROT_HYDRA, + PROT_TCP, + PROT_BINKP +} e_protocol; + +typedef enum reqstat { + REQS_DISABLED, /* Freqs not supported by the system */ + REQS_ALLOW, /* We will process file requests */ + REQS_NOTALLOW /* Freqs TEMPORARY disabled for any reason */ +} e_reqstat; + +#define HRC_OK 0 /* No errors */ +#define HRC_LOW_SPEED 1 /* Connect speed too low (shown it in EMSI) */ +#define HRC_BAD_PASSWD 2 /* Pasword failure (shown it in EMSI) */ +#define HRC_NO_ADDRESS 3 /* Expected address was not presented */ +#define HRC_NO_PROTOS 4 /* No common protocols :( */ +#define HRC_BUSY 5 /* All remote AKAs are busy */ +#define HRC_FATAL_ERR 6 /* Any other fatal handshake error */ +#define HRC_TEMP_ERR 7 /* Any other temporary handshake error */ +#define HRC_OTHER_ERR 8 /* Any other error (e.g. timeout, NO CARRIER) */ + +typedef struct sysaddr { + s_faddr addr; + bool busy; + bool good; + int flags; +} s_sysaddr; + +typedef struct { + char passwd[128]; + char challenge[128]; + int challenge_length; + bool cram_auth; +} s_session_passwd; + +typedef struct sendopts { + int fnc:1, /* Convert outgoing file names to 8+3 format */ + holdreq:1, /* Hold .REQ files? (file requests) */ + holdhold:1, /* Hold files with HOLD flavor? */ + holdfiles:1, /* Hold all files except netmail + arcmail */ + holdxt:1, /* Hold all except netmail? */ + holdall:1, /* Hold ALL trafic!? */ + hydraRH1; /* Hydra RH1 mode (EMSI only) */ +} s_sendopts; + +/* + * Handhake protocols API + */ +typedef struct handshake_protocol +{ + /* + * 1. Main pointers + */ + char *verbal_name; + char *author; + char *standard; + char *remote_data; + char *local_data; + e_protocol protocol; + + void (*init)(struct handshake_protocol *THIS); + void (*deinit)(struct handshake_protocol *THIS); + int (*incoming_session)(struct handshake_protocol *THIS); + int (*outgoing_session)(struct handshake_protocol *THIS); + + /* + * 2. Remote system information extract methods + */ + s_faddr* (*remote_address)(struct handshake_protocol *THIS); + char* (*remote_password)(struct handshake_protocol *THIS); + char* (*remote_sysop_name)(struct handshake_protocol *THIS); + char* (*remote_system_name)(struct handshake_protocol *THIS); + char* (*remote_location)(struct handshake_protocol *THIS); + char* (*remote_phone)(struct handshake_protocol *THIS); + char* (*remote_flags)(struct handshake_protocol *THIS); + char* (*remote_mailer)(struct handshake_protocol *THIS); + int (*remote_traffic)(struct handshake_protocol *THIS, s_traffic *dest); + + /* + * 3. Local system information extract methods + */ + s_faddr* (*local_address)(struct handshake_protocol *THIS); + char* (*local_password)(struct handshake_protocol *THIS); +} s_handshake_protocol; + +struct state +{ + s_node node; +const s_modemport *modemport; + char *linename; /* Verbal line name (i.e. ttyS1, tcpip, etc.) */ + time_t start_time; /* Session start time (e.g. connect time) */ + e_tcpmode tcpmode; /* Current mode to work via TCP/IP */ + e_session session; /* handshake type (EMSI, YooHoo, etc.) */ + bool valid; /* This structure contain real information */ + bool caller; /* Outgoing session */ + bool protected; /* Password protected session? */ + bool listed; /* Session with listed system? */ + bool inet; /* We are working via TCP/IP now */ + int session_rc; /* Session return code */ + s_sendopts sopts; /* Our send options (hold arcmail, etc.) */ + e_reqstat reqstat; /* Our file request processor status */ + s_override override; + s_sess_stat sess_stat; /* Try counters, hold timers, etc. */ + long connspeed; + long minspeed; + char *cidstr; /* Caller Phone/ID when we are answering */ + char *peername; /* Remote peer name than using TCP/IP */ + long peerport; /* Remote port number, we are connected to */ + char *connstr; + char *inbound; /* Inbound directory for this session */ + char *tinbound; /* Temporary inbound for this session */ + s_traffic traff_send; /* Expected outgoing traffic */ + s_traffic traff_recv; /* Expected incoming traffic */ + + s_handshake_protocol *handshake; + + s_falist *mailfor; /* Remote valid addresses */ + s_fsqueue queue; /* Send files queue */ +}; +typedef struct state s_state; + +/* s_common.c */ +int session_get_local_address(s_faddr *addr); +int session_get_remote_address(s_faddr *addr); +int session_get_remote_sysop(char **dest); +int session_get_remote_systname(char **const dest); +int session_get_remote_mailer(char **const dest); +int session_get_remote_phone(char **const dest); +int session_get_remote_location(char **const dest); +int session_is_remote_protected(void); +int session_is_remote_listed(void); +int session_get_callerid(char **const dest); +int session_get_connect(char **const dest); +int session_run_command(const char *execstr); +int override_get(s_override *dest, s_faddr addr, int line); +void init_state(s_state *pstate); +void deinit_state(s_state *pstate); + +/* s_init.c */ +int session_init_outgoing(void); +int session_init_incoming(void); + +/* s_main.c */ +extern s_state state; + +s_faddr *session_get_bestaka(s_faddr addr); +int session_addrs_lock(s_sysaddr *addrs, int anum); +int session_addrs_add(s_sysaddr **addrs, int *anum, s_faddr addr); +int session_addrs_check(s_sysaddr *addrs, int anum, const char *passwd, + const char *challenge, int challenge_length); +int session_addrs_to_falist(s_sysaddr *addrs, int anum, s_falist **dest); +int session_addrs_check_genuine(s_sysaddr *addrs, int anum, s_faddr expected); +int session_check_speed(void); +int session_check_addr(s_faddr addr); +int session_get_password(s_faddr addr, char *buffer, size_t buflen); +int session_remote_lookup(s_sysaddr *addrs, int anum); +void session_remote_log_status(void); +int session_check_password(s_faddr addr, const char *passwd); +int session_set_inbound(void); +void session_set_freqs_status(void); +void session_set_send_options(void); +void session_set_send_files(void); +int session_create_files_queue(s_sysaddr *addrs, int anum); +int session_traffic_set_incoming(s_traffic *dest); +int session_traffic_set_outgoing(s_traffic *dest); +void session_traffic(void); +void session_update_history(s_traffic *send, s_traffic *recv, int rc); +int session(void); + +/* sess_call.c */ +int call_system(s_faddr addr, const s_bforce_opts *opts); +int call_system_modem(void); +int call_system_tcpip(void); + +/* sess_answ.c */ +int answ_system(e_session type, char *connstr, int inetd); + +/* sess_stat.c */ +void session_stat_reset_counters(s_sess_stat *stat); +int session_stat_get(s_sess_stat *stat, s_faddr *addr); +int session_stat_apply_diff(s_faddr addr, s_sess_stat stat); +int session_stat_update(s_faddr *addr, s_sess_stat *stat, bool caller, int rc); + +#endif diff --git a/source/include/util.h b/source/include/util.h new file mode 100644 index 0000000..2db486e --- /dev/null +++ b/source/include/util.h @@ -0,0 +1,258 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#define DEFAULT_ZONE 2 +#define DEFAULT_NET 5020 +#define DEFAULT_NODE 0 + +#define TIMEVEC_MAX_ELEMENTS 10 + +enum { ADDR_EQ, ADDR_GT, ADDR_LT }; + +enum { + PLOCK_OK, + PLOCK_EXIST, + PLOCK_ERROR, + PLOCK_OURLOCK +}; + +enum day +{ + DAY_MONDAY, + DAY_TUESDAY, + DAY_WEDNESDAY, + DAY_THURSDAY, + DAY_FRIDAY, + DAY_SATURDAY, + DAY_SUNDAY, + DAY_ANY, + DAY_WORKDAY, + DAY_WEEKEND, + DAY_UNDEF +}; + +typedef struct faddr { + bool inetform; /* Is address in domain form? */ + int zone; /* -1 value means any?! */ + int net; + int node; + int point; + char domain[BF_MAXDOMAIN+1]; +} s_faddr; + +typedef struct timeint { + enum day day_beg; + enum day day_end; + long beg; + long end; +} s_timeint; + +typedef struct timevec { + int num; + s_timeint tvec[TIMEVEC_MAX_ELEMENTS]; +} s_timevec; + +typedef struct message { + int attr; + int cost; + time_t time; + s_faddr orig; + s_faddr dest; + char namefrom[36]; + char nameto[36]; + char subject[72]; + char *text; + char *tagline; + char *tearline; + char *origin; +} s_message; + +typedef struct packet { + s_faddr orig; + s_faddr dest; + int baud; + char password[8+1]; + s_message *msgs; + int n_msgs; +} s_packet; + +enum +{ + FILELOCK_CLEAR, + FILELOCK_READ, + FILELOCK_WRITE +}; + +#define RECODE_MAX_CHAR 255 + +typedef struct recode_table { + const char *filename; + char table[RECODE_MAX_CHAR+1]; +} s_recode_table; + +#undef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#undef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) + +#define SET_LAT_A_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define SET_LAT_a_z "abcdefghijklmnopqrstuvwxyz" +#define SET_DEC "0123456789" +#define SET_HEX "0123456789ABCDEFabcdef" +#define SET_OCT "01234567" + +#define CRC16TEST(crc) ((crc) == 0xf0b8) +#define CRC32TEST(crc) ((crc) == 0xdebb20e3L) + +#define updcrc16(cp, crc) (TableCRC16Xmodem[(((int)(crc) >> 8) & 0xff)] ^ ((crc) << 8) ^ (cp)) +#define updcrc32(cp, crc) (TableCRC32CCITT[((int)(crc) ^ cp) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF)) + +#define localtogmt(t) ((t) - time_gmtoffset()*60) +#define gmttolocal(t) ((t) + time_gmtoffset()*60) + +#define timer_set(ptr, v) (time_settimer(ptr, v)) +#define timer_expired(tm) (time(NULL) > (tm)) +#define timer_running(tm) ((tm) > 0) +#define timer_timeleft(tm) (time_timeleft(tm)) + +#define recode_file_out(str) recode(str, &recode_table_out, conf_string(cf_recode_file_out)); +#define recode_file_in(str) recode(str, &recode_table_in, conf_string(cf_recode_file_in)); +#define recode_intro_in(str) recode(str, &recode_table_in, conf_string(cf_recode_intro_in)); + +extern s_recode_table recode_table_in; +extern s_recode_table recode_table_out; +extern unsigned long TableCRC32CCITT[]; +extern unsigned short TableCRC16Xmodem[]; +extern unsigned short TableCRC16CCITT[]; + +/* u_crc.c */ +unsigned long getcrc32ccitt(const unsigned char *buffer, size_t buflen); +unsigned short getcrc16xmodem(const unsigned char *buffer, size_t buflen); +unsigned short getcrc16ccitt(const unsigned char *buffer, size_t buflen); + +/* u_file.c */ +int file_lock(FILE *fp, bool exclusive); +void file_unlock(FILE *fp); +int file_lock_wait(FILE *fp, bool exclusive); +bool file_name_issafe(int ch); +char *file_name_makesafe(char *filename); +char *file_getname(char *filename); +char *file_gettmp(void); +char *file_get_dos_name(char *buffer, const char *filename); +bool is_directory(const char *dirname); +bool is_regfile(const char *filename); +int directory_create(const char *dirname, mode_t access_mode); +FILE *file_open(const char *path, const char *mode); +int file_close(FILE *stream); + +/* u_ftn.c */ +int ftn_addrparse(s_faddr *addr, const char *s, bool wildcard); +char *ftn_addrstr_fido(char *buf, s_faddr addr); +char *ftn_addrstr_inet(char *buf, s_faddr addr); +char *ftn_addrstr(char *buf, s_faddr addr); +int ftn_addrcomp(s_faddr addr1, s_faddr addr2); +int ftn_addrcomp_logic(s_faddr addr1, int operator, s_faddr addr2); +int ftn_addrcomp_mask(s_faddr addr, s_faddr mask); +int ftn_addrsmetric(s_faddr addr1, s_faddr addr2); + +/* u_md5.c */ +void md5_get(const unsigned char *data, size_t length, unsigned char *digest); +void md5_cram_get(const unsigned char *secret, const unsigned char *challenge, + int challenge_length, unsigned char *digest); + +/* u_misc.c */ +void *xmalloc(size_t size); +void *xrealloc(void *buf, size_t size); +void *xmemcpy(const void *buffer, size_t buflen); +char *strparse(char *str, char **next, int quoted); +int strcasemask(const char *str, const char *mask); +int checkmasks(const char *masks, const char *str); +char *buffer_putlong(char *buffer, long val); +char *buffer_putint(char *buf, int val); +long buffer_getlong(const char *buf); +int buffer_getint(const char *buf); +void printf_usage(const char *ident, const char *fmt, ...); + +/* u_pkt.c */ +int pkt_createpacket(const char *pktname, const s_packet *pkt); + +/* u_plock.c */ +int plock_check(const char *lockname); +int plock_create(const char *lockname); +int plock_remove(const char *lockname); +int plock_link(const char *lockname, const char *tmpname); + +/* u_recode.c */ +char *recode(char *src, s_recode_table *tab, const char *filename); + +/* u_string.c */ +char *xstrcpy(const char *src); +char *xstrcat(char *src, const char *add); +char *strnxcpy(char *dst, const char *src, size_t len); +char *strnxcat(char *dst, const char *src, size_t len); +char *string_token(char *str, char **next, const char *delim, int quoted); +char *string_chomp(char *str); +const char *string_casestr(const char *string, const char *substr); +const char *string_casechr(const char *str, int ch); +char *string_toupper(char *str); +char *string_tolower(char *str); +bool string_isupper(const char *str); +bool string_islower(const char *str); +char *string_trimright(char *str); +char *string_trimleft(char *str); +char *string_trimboth(char *str); +char *string_printable_buffer(const char *buffer, size_t buflen); +const char *string_printable(const char *str); +char *string_replchar(char *str, char oldchar, char newchar); +int string_parse(char **dest, int items, char *str, int separator); +int string_parse_regular(char **dest, int items, char *str); +char *string_translate(const char *str, const char *find, const char *repl); +char *string_humansize(char *buffer, size_t size); +int string_get_escape(char **pptr); +int string_dequote(char *dst, char *src); +char *string_concat(const char *str, ...); +void string_bin_to_hex(char *string, const char *binptr, int binlen); +int string_hex_to_bin(char *binptr, const char *string); +bool string_is_empty(const char *string); + +/* u_time.c */ +int time_settimer(time_t *timer, int value); +int time_timerout(time_t timer); +int time_timeleft(time_t timer); +int time_elapsed(time_t since_time); +char *time_string_format(char *buffer, size_t buflen, const char *fmt, time_t t); +char *time_string_long(char *buffer, size_t buflen, time_t t); +char *time_string_log(char *buffer, size_t buflen, time_t t); +char *time_string_msghdr(char *buffer, time_t t); +long time_gmtoffset(void); +char *time_string_gmtoffset(char *buffer); +char *time_string_timer(char *buffer, int timer); +char *time_string_approx_interval(char *buffer, int seconds); +int time_check(const char *str, struct tm *now); +int time_checkintervals(const char *timestr, struct tm *now); +int timevec_add(s_timevec *dest, int day_beg, int day_end, long beg, long end); +int timevec_parse(s_timevec *dest, const char *str); +int timevec_parse_list(s_timevec *dest, const char *str); +int timevec_check(const s_timevec *tv, const struct tm *now); +char *timevec_string(char *buffer, const s_timevec *tv, size_t buflen); +bool timevec_isdefined(const s_timevec *tv); +bool timevec_isnow(const s_timevec *tv, const struct tm *now); + +#endif /* _UTIL_H_ */ diff --git a/source/include/version.h b/source/include/version.h new file mode 100644 index 0000000..3f679f3 --- /dev/null +++ b/source/include/version.h @@ -0,0 +1,33 @@ +/* + * binkleyforce -- unix FTN mailer project + * + * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 + * + * 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. + * + * $Id$ + */ + +#ifndef _VERSION_H_ +#define _VERSION_H_ + + +#define BF_PRODCODE 0xfe +#define BF_NAME "binkleyforce" +#define BF_RDATE "n/a" +#define BF_VERSION RELEASE_VERSION +#define BF_CDATE __DATE__ __TIME__ +#define BF_REG "free software" +#define BF_COPYRIGHT "(c) 1997-2000 by Alexander Belkin" + +#define BF_BANNERVER BF_NAME" "BF_VERSION"/"BF_OS + +#define BF_EMSI_NUM "fe" +#define BF_EMSI_NAME BF_NAME +#define BF_EMSI_VER BF_VERSION"/"BF_OS +#define BF_EMSI_REG BF_REG + +#endif diff --git a/source/install-sh b/source/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/source/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