From 69f117bf78291ed6d96593cb1cebefb8fbb6bfb2 Mon Sep 17 00:00:00 2001 From: Evgeniy Kozhuhovskiy Date: Thu, 30 Dec 2004 16:00:36 +0000 Subject: [PATCH] Initial revision --- CHANGES | 60 + CHANGES.kst | 67 + CHANGES.ugenk | 26 + COPYING | 340 ++ INSTALL | 175 + INSTALL.ru | 131 + README | 32 + README.kst | 14 + README.ugenk | 14 + SYSLOG | 10 + TODO | 11 + build-stamp | 0 configure-stamp | 0 contrib/bfha/README | 19 + contrib/bfha/bfha.pl | 575 +++ contrib/bflan | 384 ++ contrib/callout.sh | 229 + contrib/init.d/bforce | 51 + contrib/init.d/bforce.debian | 44 + contrib/outman | 366 ++ contrib/timesync.tcl | 116 + contrib/u-srif/INFO | 6 + contrib/u-srif/conf/report.footer | 27 + contrib/u-srif/conf/report.header | 2 + contrib/u-srif/conf/u-srif.aliases | 6 + contrib/u-srif/conf/u-srif.conf | 21 + contrib/u-srif/conf/u-srif.dirs | 42 + contrib/u-srif/lib/uconfig.py | 163 + contrib/u-srif/lib/udbase.py | 151 + contrib/u-srif/lib/ufido.py | 181 + contrib/u-srif/lib/unodestat.py | 102 + contrib/u-srif/lib/utmpl.py | 97 + contrib/u-srif/lib/uutil.py | 54 + contrib/u-srif/u-srif-index.py | 50 + contrib/u-srif/u-srif-lookup.py | 35 + contrib/u-srif/u-srif.py | 182 + debian/Makefile | 242 + debian/Makefile.am | 3 + debian/Makefile.in | 242 + debian/README.Debian | 6 + debian/bfindex.1 | 25 + debian/bforce.1 | 68 + debian/bforce.postinst.debhelper | 10 + debian/bforce.postrm.debhelper | 5 + debian/bforce.prerm.debhelper | 9 + debian/bforce.substvars | 1 + debian/bfstat.1 | 47 + debian/changelog | 27 + debian/compat | 1 + debian/conffiles | 6 + debian/control | 18 + debian/copyright | 14 + debian/default | 2 + debian/dirs | 13 + debian/docs | 9 + debian/init.d | 61 + debian/nlookup.1 | 30 + debian/outman.1 | 36 + debian/postinst | 57 + debian/postrm | 38 + debian/preinst | 44 + debian/prerm | 39 + debian/rules | 111 + debian/rules-1 | 96 + examples/bforce.conf | 567 +++ examples/bforce.passwd | 9 + examples/bforce.subst | 33 + examples/freq.aliases | 6 + examples/freq.dirs | 10 + patch-stamp | 2 + rpm/bforce.spec | 70 + rpm/buildrpm.sh | 31 + source/.version | 1 + source/Makefile | 185 + source/Makefile.in | 185 + source/bforce/bforce.c | 485 ++ source/bforce/conf_deinit.c | 135 + source/bforce/conf_get.c | 108 + source/bforce/conf_proc.c | 997 ++++ source/bforce/conf_read.c | 457 ++ source/bforce/daemon.c | 1041 ++++ source/bforce/daemon_branch.c | 161 + source/bforce/daemon_call.c | 202 + source/bforce/daemon_lines.c | 106 + source/bforce/expression.tab.c | 1733 +++++++ source/bforce/expression.y | 443 ++ source/bforce/expression_lex.c | 174 + source/bforce/freq_bark.c | 18 + source/bforce/freq_proc.c | 406 ++ source/bforce/freq_srif.c | 153 + source/bforce/freq_wazoo.c | 113 + source/bforce/io_modem.c | 465 ++ source/bforce/io_tcpip.c | 250 + source/bforce/io_unix_lock.c | 379 ++ source/bforce/io_unix_modem.c | 242 + source/bforce/io_unix_tio.c | 336 ++ source/bforce/io_unix_tty.c | 438 ++ source/bforce/logger.c | 570 +++ source/bforce/nodelist.c | 585 +++ source/bforce/os_os2.c | 15 + source/bforce/os_unix.c | 469 ++ source/bforce/os_w32.c | 15 + source/bforce/outb_bsy.c | 424 ++ source/bforce/outb_flo.c | 228 + source/bforce/outb_fsqueue.c | 255 + source/bforce/outb_getname.c | 111 + source/bforce/outb_scan.c | 522 ++ source/bforce/outb_sysqueue.c | 302 ++ source/bforce/prot_binkp.c | 698 +++ source/bforce/prot_binkp_api.c | 283 ++ source/bforce/prot_binkp_misc.c | 740 +++ source/bforce/prot_common.c | 1559 ++++++ source/bforce/prot_emsi.c | 842 ++++ source/bforce/prot_emsi_api.c | 480 ++ source/bforce/prot_emsi_misc.c | 817 +++ source/bforce/prot_hydra.c | 2136 ++++++++ source/bforce/prot_xmrecv.c | 15 + source/bforce/prot_xmsend.c | 15 + source/bforce/prot_yoohoo.c | 591 +++ source/bforce/prot_yoohoo_api.c | 363 ++ source/bforce/prot_zmmisc.c | 1180 +++++ source/bforce/prot_zmrecv.c | 561 +++ source/bforce/prot_zmsend.c | 728 +++ source/bforce/sess_answ.c | 138 + source/bforce/sess_call.c | 716 +++ source/bforce/sess_common.c | 187 + source/bforce/sess_init.c | 507 ++ source/bforce/sess_main.c | 872 ++++ source/bforce/sess_stat.c | 304 ++ source/bforce/u_crc.c | 206 + source/bforce/u_file.c | 312 ++ source/bforce/u_ftn.c | 525 ++ source/bforce/u_md5.c | 336 ++ source/bforce/u_misc.c | 336 ++ source/bforce/u_pkt.c | 220 + source/bforce/u_plock.c | 203 + source/bforce/u_recode.c | 141 + source/bforce/u_string.c | 932 ++++ source/bforce/u_time.c | 621 +++ source/bfutil/bfindex.c | 286 ++ source/bfutil/bfstat.c | 338 ++ source/bfutil/nlookup.c | 155 + source/config.guess | 951 ++++ source/config.status | 1011 ++++ source/config.sub | 955 ++++ source/configure | 7427 ++++++++++++++++++++++++++++ source/configure.in | 109 + source/include/acconfig.h | 22 + source/include/bforce.h | 191 + source/include/config.h | 145 + source/include/config.h.in | 144 + source/include/confread.h | 363 ++ source/include/daemon.h | 93 + source/include/freq.h | 70 + source/include/includes.h | 143 + source/include/io.h | 230 + source/include/logger.h | 85 + source/include/nodelist.h | 168 + source/include/os.h | 72 + source/include/outbound.h | 209 + source/include/prot_binkp.h | 160 + source/include/prot_common.h | 136 + source/include/prot_emsi.h | 221 + source/include/prot_yoohoo.h | 64 + source/include/prot_zmodem.h | 222 + source/include/session.h | 223 + source/include/util.h | 258 + source/include/version.h | 33 + source/install-sh | 251 + 169 files changed, 50779 insertions(+) create mode 100644 CHANGES create mode 100644 CHANGES.kst create mode 100644 CHANGES.ugenk create mode 100644 COPYING create mode 100644 INSTALL create mode 100644 INSTALL.ru create mode 100644 README create mode 100644 README.kst create mode 100644 README.ugenk create mode 100644 SYSLOG create mode 100644 TODO create mode 100644 build-stamp create mode 100644 configure-stamp create mode 100644 contrib/bfha/README create mode 100644 contrib/bfha/bfha.pl create mode 100644 contrib/bflan create mode 100644 contrib/callout.sh create mode 100644 contrib/init.d/bforce create mode 100644 contrib/init.d/bforce.debian create mode 100644 contrib/outman create mode 100644 contrib/timesync.tcl create mode 100644 contrib/u-srif/INFO create mode 100644 contrib/u-srif/conf/report.footer create mode 100644 contrib/u-srif/conf/report.header create mode 100644 contrib/u-srif/conf/u-srif.aliases create mode 100644 contrib/u-srif/conf/u-srif.conf create mode 100644 contrib/u-srif/conf/u-srif.dirs create mode 100644 contrib/u-srif/lib/uconfig.py create mode 100644 contrib/u-srif/lib/udbase.py create mode 100644 contrib/u-srif/lib/ufido.py create mode 100644 contrib/u-srif/lib/unodestat.py create mode 100644 contrib/u-srif/lib/utmpl.py create mode 100644 contrib/u-srif/lib/uutil.py create mode 100644 contrib/u-srif/u-srif-index.py create mode 100644 contrib/u-srif/u-srif-lookup.py create mode 100644 contrib/u-srif/u-srif.py create mode 100644 debian/Makefile create mode 100644 debian/Makefile.am create mode 100644 debian/Makefile.in create mode 100644 debian/README.Debian create mode 100644 debian/bfindex.1 create mode 100644 debian/bforce.1 create mode 100644 debian/bforce.postinst.debhelper create mode 100644 debian/bforce.postrm.debhelper create mode 100644 debian/bforce.prerm.debhelper create mode 100644 debian/bforce.substvars create mode 100644 debian/bfstat.1 create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/conffiles create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/default create mode 100644 debian/dirs create mode 100644 debian/docs create mode 100644 debian/init.d create mode 100644 debian/nlookup.1 create mode 100644 debian/outman.1 create mode 100644 debian/postinst create mode 100644 debian/postrm create mode 100644 debian/preinst create mode 100644 debian/prerm create mode 100755 debian/rules create mode 100755 debian/rules-1 create mode 100644 examples/bforce.conf create mode 100644 examples/bforce.passwd create mode 100644 examples/bforce.subst create mode 100644 examples/freq.aliases create mode 100644 examples/freq.dirs create mode 100644 patch-stamp create mode 100644 rpm/bforce.spec create mode 100755 rpm/buildrpm.sh create mode 100644 source/.version create mode 100644 source/Makefile create mode 100644 source/Makefile.in create mode 100644 source/bforce/bforce.c create mode 100644 source/bforce/conf_deinit.c create mode 100644 source/bforce/conf_get.c create mode 100644 source/bforce/conf_proc.c create mode 100644 source/bforce/conf_read.c create mode 100644 source/bforce/daemon.c create mode 100644 source/bforce/daemon_branch.c create mode 100644 source/bforce/daemon_call.c create mode 100644 source/bforce/daemon_lines.c create mode 100644 source/bforce/expression.tab.c create mode 100644 source/bforce/expression.y create mode 100644 source/bforce/expression_lex.c create mode 100644 source/bforce/freq_bark.c create mode 100644 source/bforce/freq_proc.c create mode 100644 source/bforce/freq_srif.c create mode 100644 source/bforce/freq_wazoo.c create mode 100644 source/bforce/io_modem.c create mode 100644 source/bforce/io_tcpip.c create mode 100644 source/bforce/io_unix_lock.c create mode 100644 source/bforce/io_unix_modem.c create mode 100644 source/bforce/io_unix_tio.c create mode 100644 source/bforce/io_unix_tty.c create mode 100644 source/bforce/logger.c create mode 100644 source/bforce/nodelist.c create mode 100644 source/bforce/os_os2.c create mode 100644 source/bforce/os_unix.c create mode 100644 source/bforce/os_w32.c create mode 100644 source/bforce/outb_bsy.c create mode 100644 source/bforce/outb_flo.c create mode 100644 source/bforce/outb_fsqueue.c create mode 100644 source/bforce/outb_getname.c create mode 100644 source/bforce/outb_scan.c create mode 100644 source/bforce/outb_sysqueue.c create mode 100644 source/bforce/prot_binkp.c create mode 100644 source/bforce/prot_binkp_api.c create mode 100644 source/bforce/prot_binkp_misc.c create mode 100644 source/bforce/prot_common.c create mode 100644 source/bforce/prot_emsi.c create mode 100644 source/bforce/prot_emsi_api.c create mode 100644 source/bforce/prot_emsi_misc.c create mode 100644 source/bforce/prot_hydra.c create mode 100644 source/bforce/prot_xmrecv.c create mode 100644 source/bforce/prot_xmsend.c create mode 100644 source/bforce/prot_yoohoo.c create mode 100644 source/bforce/prot_yoohoo_api.c create mode 100644 source/bforce/prot_zmmisc.c create mode 100644 source/bforce/prot_zmrecv.c create mode 100644 source/bforce/prot_zmsend.c create mode 100644 source/bforce/sess_answ.c create mode 100644 source/bforce/sess_call.c create mode 100644 source/bforce/sess_common.c create mode 100644 source/bforce/sess_init.c create mode 100644 source/bforce/sess_main.c create mode 100644 source/bforce/sess_stat.c create mode 100644 source/bforce/u_crc.c create mode 100644 source/bforce/u_file.c create mode 100644 source/bforce/u_ftn.c create mode 100644 source/bforce/u_md5.c create mode 100644 source/bforce/u_misc.c create mode 100644 source/bforce/u_pkt.c create mode 100644 source/bforce/u_plock.c create mode 100644 source/bforce/u_recode.c create mode 100644 source/bforce/u_string.c create mode 100644 source/bforce/u_time.c create mode 100644 source/bfutil/bfindex.c create mode 100644 source/bfutil/bfstat.c create mode 100644 source/bfutil/nlookup.c create mode 100755 source/config.guess create mode 100755 source/config.status create mode 100755 source/config.sub create mode 100755 source/configure create mode 100644 source/configure.in create mode 100644 source/include/acconfig.h create mode 100644 source/include/bforce.h create mode 100644 source/include/config.h create mode 100644 source/include/config.h.in create mode 100644 source/include/confread.h create mode 100644 source/include/daemon.h create mode 100644 source/include/freq.h create mode 100644 source/include/includes.h create mode 100644 source/include/io.h create mode 100644 source/include/logger.h create mode 100644 source/include/nodelist.h create mode 100644 source/include/os.h create mode 100644 source/include/outbound.h create mode 100644 source/include/prot_binkp.h create mode 100644 source/include/prot_common.h create mode 100644 source/include/prot_emsi.h create mode 100644 source/include/prot_yoohoo.h create mode 100644 source/include/prot_zmodem.h create mode 100644 source/include/session.h create mode 100644 source/include/util.h create mode 100644 source/include/version.h create mode 100755 source/install-sh 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